diff options
Diffstat (limited to 'java/JACE/netsvcs/Naming/NameAcceptor.java')
-rw-r--r-- | java/JACE/netsvcs/Naming/NameAcceptor.java | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/java/JACE/netsvcs/Naming/NameAcceptor.java b/java/JACE/netsvcs/Naming/NameAcceptor.java new file mode 100644 index 00000000000..7e7be457d70 --- /dev/null +++ b/java/JACE/netsvcs/Naming/NameAcceptor.java @@ -0,0 +1,313 @@ +/************************************************* + * + * = PACKAGE + * netsvcs.Naming + * + * = FILENAME + * NameAcceptor.java + * + *************************************************/ +package JACE.netsvcs.Naming; + +import java.io.*; +import java.net.*; +import java.util.*; +import JACE.OS.*; +import JACE.Misc.*; +import JACE.Connection.*; +import JACE.Reactor.*; +import JACE.ASX.TimeValue; +import JACE.netsvcs.Server; + +/** + * Server for the naming service. + * Listens on the specified port (command line option) and launches + * NameHandlers when connections are made. + * <P> + * The hash table for the mapping and a timer queue are created here. + * Periodically, if it has been changed, the mapping is saved to a file. + * If the data file exists at load time, it is read from disk. Currently, + * the service stores the entire mapping in one Hashtable (which is probably + * kept in memory at all times). + * <P> + * <B>Valid command line arguments:</B> + * <PRE> + * -f (file name) File name of the database + * (Default is namedata.dat) + * -p (port number) Port to listen on for clients + * -d Enable debugging + * -t (time sec) How often to save the database (default 60 sec) + * -a (class name) Specify ActivateStrategy + * (Default is multi-threaded) + * </PRE> + * + *@see NameHandler + * + *@author Everett Anderson + * + */ +public class NameAcceptor extends Server +{ + /** + * Constructor + */ + public NameAcceptor () + { + // Set the name in case we are not using the service + // configurator + name ("Naming Service"); + + // Create the hash table and timer queue + this.mapping_ = new Hashtable (); + this.tq_ = new TimerQueue (true); + } + + /** + * Simple main program. See the class description for more + * information about command line arguments. + */ + public static void main (String [] args) + { + // Simple main program to get things rolling + NameAcceptor na = new NameAcceptor(); + + na.init(args); + } + + /** + * Check to see if the mapping has been modified since the last + * save. + */ + synchronized boolean modifiedMapping () + { + return mappingWasModified_; + } + + /** + * Set the modified state of the mapping. + */ + synchronized void modifiedMapping (boolean value) + { + mappingWasModified_ = value; + } + + /** + * Cancels the timer which was used to save the mapping, then delegates + * to Server.fini (). + * + *@return -1 on failure, 0 on success + */ + public int fini () + { + if (!done () && tq_ != null) + tq_.cancelTimer (this); + + return super.fini (); + } + + /** + * Read the data file (if it exists) and schedule a periodic timer + * to save it at intervals. At the end, this delegates to + * Server.initialize () (which currently sets the default + * activation scheme if it wasn't defined on the command line). + * + *@see Server#initialize + *@return -1 on failure, 0 on success + */ + protected int initialize () + { + this.loadTable (); + + this.tq_.scheduleTimer (this, + null, + new TimeValue (this.updateInterval_), + new TimeValue (this.updateInterval_)); + + // Use whatever default ActivateStrategy is defined in the + // Server class (unless specified in parseArgs) + return super.initialize (); + } + + /** + * Create a new NameHandler instance. + */ + protected SvcHandler makeSvcHandler () + { + return new NameHandler (mapping_); + } + + /** + * 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 <file name> File name of the database"); + ACE.ERROR (" (Default is namedata.dat)"); + ACE.ERROR ("-p <port number> Port to listen on for clients"); + ACE.ERROR ("-d Enable debugging"); + ACE.ERROR ("-t <time sec> How often to save the database"); + ACE.ERROR (" (Default is 60 seconds)"); + ACE.ERROR ("-a <class name> Specify ActivateStrategy"); + ACE.ERROR (" (Default is multi-threaded"); + } + + /** + * 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; + String s; + GetOpt opt = new GetOpt (args, "p:f:t:da:", true); + + try { + + while ((c = opt.next ()) != -1) { + switch (c) + { + case 'f': + this.filename_ = opt.optarg (); + break; + case 't': + try { + this.updateInterval_ = Integer.parseInt (opt.optarg ()); + } catch (NumberFormatException e) { + ACE.ERROR ("Invalid interval specified: " + e.getMessage ()); + return -1; + } + break; + case 'd': + ACE.enableDebugging (); + ACE.DEBUG ("Debugging is enabled"); + break; + case 'p': + if (!port (opt.optarg ())) + return -1; + break; + case 'a': + Object strategy = newStrategyInstance (opt.optarg (), + "ActivateStrategy"); + if (strategy == null) + return -1; + + activateStrategy ((ActivateStrategy) strategy); + 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; + } + + /** + * Loads the hash table into memory from the specified + * file. Uses ObjectInputStream. + */ + protected void loadTable () + { + File file = new File(this.filename_); + FileInputStream fis; + ObjectInputStream ois; + + Hashtable ht = null; + + try { + + if ((file.exists()) && (file.canRead())) { + + fis = new FileInputStream (file); + + ois = new ObjectInputStream(fis); + + ht = (Hashtable)ois.readObject(); + } else + return; + } catch (ClassNotFoundException e) { + ACE.ERROR(e); + } catch (StreamCorruptedException e) { + ACE.ERROR(e); + } catch (SecurityException e) { + ACE.ERROR(e); + } catch (IOException e) { + ACE.ERROR(e); + } + + if (ht != null) + this.mapping_ = ht; + + } + + /** + * Writes the table out to the specified file if it has been modified. + */ + protected void saveTable () + { + if (!modifiedMapping ()) + return; + + FileOutputStream fos; + ObjectOutputStream oos; + + try { + + fos = new FileOutputStream(this.filename_); + oos = new ObjectOutputStream(fos); + + synchronized (this.mapping_) { + oos.writeObject(this.mapping_); + + modifiedMapping (false); + } + + oos.flush(); + + oos.close(); + + } catch (OptionalDataException e) { + ACE.ERROR(e); + } catch (NotSerializableException e) { + ACE.ERROR(e); + } catch (IOException e) { + ACE.ERROR(e); + } + } + + /** + * Call back for the TimerQueue. This calls the method to save the + * hash table. The default time out is 60 seconds. + */ + public int handleTimeout (TimeValue tv, Object obj) + { + this.saveTable(); + + return 0; + } + + // Mapping data structure + Hashtable mapping_ = null; + + // Default file name + String filename_ = "namedata.dat"; + + // How often to save the table (seconds) + int updateInterval_ = 60; + + // Calls handleTimeout at updateInterval_ intervals + TimerQueue tq_ = null; + + boolean mappingWasModified_ = false; +} + |