tokenacceptor.java

来自「java版ace,java程序员值得一看」· Java 代码 · 共 354 行

JAVA
354
字号
package JACE.netsvcs.Token;

import java.io.*;
import java.net.*;
import java.util.*;
import JACE.OS.*;
import JACE.Misc.*;
import JACE.Connection.*;
import JACE.netsvcs.Server;

/**
 * Server for the token service.  Launches TokenRequestHandlers as
 * connections are made.  Currently, the activation strategy must be
 * thread per connection since the operations are allowed to block
 * during acquires, etc.
 * <P>
 * Two types of locks are supported by default -- Mutex and RWMutex.
 * New lock types can be added from the command line without changing
 * any code in the service.  To do this, just create a class which
 * implements the LockHandler interface.
 * <P>
 * When a request for a new lock comes in, a LockHandler of the corresponding
 * type is created and a mapping is created between the lock name and the
 * handler.  Later requests reuse that mapping.
 * <P>
 * <B>Valid command line arguments:</B>
 * <PRE>
 *    -f (class name):(type)  Specify a LockHandler for a type of lock");
 *    -p (port number)        Port to listen on for clients");
 *    -d                      Enable debugging messages");
 * </PRE>
 *
 *@see JACE.netsvcs.Server
 *@see TokenRequestHandler
 *@see LockHandler
 *@see LockTypes
 */
public class TokenAcceptor extends Server
{ 
  protected void addDefaultFactories() throws ClassNotFoundException {
    addHandlerFactory(LockTypes.MUTEX,
		      Class.forName("JACE.netsvcs.Token.MutexHandler"));
    addHandlerFactory(LockTypes.RWLOCK,
		      Class.forName("JACE.netsvcs.Token.RWMutexHandler"));
  }
  
  /**
   * Default constructor.
   */
  public TokenAcceptor() {

    // Set the name in case we aren't using the service configurator.
    name ("Token Service");

    lockHandlerMap_ = new Hashtable();
    handlerFactoryMap_ = new Hashtable();
    clientHandlerMap_ = new Hashtable ();
  }
  
  /**
   * Add a map between a type of lock and the factory which
   * creates LockHandler instances that handle it.
   *
   *@see LockTypes
   *@param type number representing the type of lock
   *@param factory Class object for a LockHandler class
   */
  public void addHandlerFactory(Integer type, Class factory) {
    handlerFactoryMap_.put(type, factory);
  }
  
  /**
   * Add a map between a type of lock and the factory which
   * creates LockHandler instances that handle it.
   *
   *@see LockTypes
   *@param type number representing the type of lock
   *@param factory Class object for a LockHandler class
   */
  public void addHandlerFactory(int type, Class factory) {
    addHandlerFactory(new Integer(type), factory);
  }
  
  /**
   * Remove the LockHandler factory which handles locks
   * of the specified type.
   *
   *@param type type of LockHandler to cease supporting
   *@return the LockHandler instance (or null if not found)
   */
  public Object removeHandlerFactory(Integer type) {
    return handlerFactoryMap_.remove(type);
  }
  
  /**
   * Remove the LockHandler factory which handles locks
   * of the specified type.
   *
   *@param type type of LockHandler to cease supporting
   *@return the LockHandler instance (or null if not found)
   */
  public Object removeHandlerFactory(int type) {
    return handlerFactoryMap_.remove(new Integer(type));
  }

  /**
   * Retrieve the LockHandler corresponding to the given name
   * or create a new one if it doesn't exist.  This is called by
   * TokenRequestHandlers.
   *
   *@param lockName name of the lock to retrieve or create a LockHandler for
   *@param lockType type of the lock
   *@return LockHandler which handles the lock with that name
   */
  public LockHandler getLockHandler (String lockName, 
				     int lockType) {
    synchronized (lockHandlerMap_) {
      
      Object obj = lockHandlerMap_.get(lockName);
      
      if (obj != null)
	return (LockHandler)obj;
      else {
	LockHandler handler = newHandler (lockType);
	lockHandlerMap_.put (lockName, handler);
	return handler;
      }
    }
  }
  
  /**
   * Create a new LockHandler of the specified type.
   *
   *@param type type of LockHandler to create
   *@return a new LockHandler instance
   */
  protected LockHandler newHandler (int type) {
    ACE.DEBUG ("Creating new handler of type " + type);
    Object factoryObj = handlerFactoryMap_.get(new Integer(type));
    if (factoryObj == null) 
      return null;
    
    Class factory = (Class)factoryObj;
    LockHandler handler = null;
    
    try {
      handler = (LockHandler)factory.newInstance();
    } catch (InstantiationException e) {
      ACE.ERROR("Can't create a handler of type " + type);
    } catch (IllegalAccessException e) {
      ACE.ERROR("Handler of type " + type +
		" must have a default constructor");
    }
    return handler;
  }
  
  /**
   * Simple main program.  See the class description for more
   * information about command line arguments.
   */
  public static void main(String args[]) {
    TokenAcceptor ta = new TokenAcceptor();
    
    ta.init(args);
  }
  
  /**
   * Create a new TokenRequestHandler instance.
   */
  protected SvcHandler makeSvcHandler() 
  {
    return new TokenRequestHandler();
  }
  
  /**
   * Sets up the default factories so the user can override them on
   * the command line, then delegates back to Server.init (String[]).
   *
   *@see JACE.netsvcs.Server#init
   *@param args command line arguments
   *@return -1 on failure, 0 on success
   */
  public int init(String [] args) {
    try {
      addDefaultFactories ();
    } catch (ClassNotFoundException e) {
      ACE.ERROR ("Can't find default factory " + e.getMessage ());
      return -1;
    }

    return super.init (args);
  }
  
  /**
   * Prints out the valid command line arguments.  See the class
   * description for more information.  Called by Server.init when
   * parseArgs returns -1.
   */
  protected void printUsage ()
  {
    ACE.ERROR ("Valid options:\n");
    ACE.ERROR ("-f <class name>:<type>  Specify a handler for a type of lock");
    ACE.ERROR ("-p <port number>        Port to listen on for clients");
    ACE.ERROR ("-d                      Enable debugging messages");
  }

  /**
   * Parses the command line arguments.  See the class description
   * for more information.
   *
   *@param args command line arguments
   *@return -1 on failure, 0 on success
   */
  protected int parseArgs(String [] args) 
  {
    int c = 0;
    GetOpt opt = new GetOpt(args, "p:f:d", true);
    
    try {

      while ((c = opt.next ()) != -1) {
	switch (c) 
	  {
	  case 'd':
	    ACE.enableDebugging ();
	    ACE.DEBUG ("Debugging is enabled");
	    break;
	  case 'p':
	    if (!port (opt.optarg ()))
	      return -1;
	    break;
	  case 'f':
	    if (newHandlerFactory (opt.optarg ()) < 0)
	      return -1;
	    break;
	  default:
	    ACE.ERROR("Unknown argument: " + (char)c);
	    return -1;
	  }
      }
    } catch (ArrayIndexOutOfBoundsException e) {
      ACE.ERROR ("Option -" + (char)c + " requires an argument");
      return -1;
    }
    
    return 0;
  }

  /**
   * Load the Class for the specified LockHandler and create a mapping
   * from its type to the Class instance.  Used to parse the command
   * line pair of (class name):(type).
   *
   *@param nameAndType (class name):(type) pair from the command line
   *@return -1 on failure, 0 on success
   */
  protected int newHandlerFactory (String nameAndType)
  {
    int colon = nameAndType.lastIndexOf (':');

    if (colon < 1) {
      ACE.ERROR ("Invalid -f <class name>:<type num> for handler: " + 
		 nameAndType);
      return -1;
    }

    int type = 0;
    try {
      type = Integer.parseInt (nameAndType.substring (colon + 1));
    } catch (NumberFormatException e) {
      ACE.ERROR ("Invalid token type: " + e.getMessage ());
      return -1;
    }

    String name = nameAndType.substring (0, colon);

    Class factory;
    try {
      factory = Class.forName (name);
    } catch (ClassNotFoundException e) {
      ACE.ERROR (e.getMessage ());
      return -1;
    }

    addHandlerFactory (type, factory);
    ACE.DEBUG ("New handler " + name + " with type " + type);

    return 0;
  }

  /**
   * Create a mapping between a client ID and a LockHandler.  This is
   * only used by TokenRequestHandlers in order to keep track of which
   * locks a client touches.  That way, if/when a client disconnects,
   * all its locks can be abandoned successfully.
   *
   *@param clientID client identification (key in the mapping)
   *@param handler LockHandler to map to (value in the mapping)
   *
   */
  void addClientLockHandler (String clientID, 
			     LockHandler handler)
  {
    Object obj = clientHandlerMap_.get (clientID);
    if (obj == null) {
      // Probably won't have more than 10 locks per client ID, and the Vector
      // should resize automatically even if someone does.
      Vector handlerList = new Vector (10);
      handlerList.addElement (handler);
      clientHandlerMap_.put (clientID, handlerList);
    } else {
      Vector handlerList = (Vector)obj;
      int alreadyThereIndex = handlerList.indexOf (handler);
      if (alreadyThereIndex == -1)
	handlerList.addElement (handler);
    }
  }

  /**
   * Called by TokenRequestHandlers to remove a specified client ID
   * from the client ID to LockHandler mapping.
   */
  void removeClient (String clientID)
  {
    clientHandlerMap_.remove (clientID);
  }

  /**
   * Called by TokenRequestHandlers to obtain a list of all LockHandlers
   * accessed by a particular client.  Useful for abandoning the locks.
   */
  Enumeration getClientLockHandlers (String clientID)
  {
    Object obj = clientHandlerMap_.get (clientID);
    if (obj == null)
      return null;
    else
      return ((Vector)obj).elements ();
  }

  // These should be replaced by weak hash maps when available
  
  // Map consisting of (token name) to (LockHandler instance) pairs
  private Hashtable lockHandlerMap_;
  
  // Map consisting of (Integer token type) to (Class instance for 
  // corresponding LockHandler class)
  private Hashtable handlerFactoryMap_;

  // Map consisting of (client ID) to (Vector of LockHandler) pairs
  private Hashtable clientHandlerMap_;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?