summaryrefslogtreecommitdiff
path: root/java/JACE/netsvcs/Naming/NameAcceptor.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/JACE/netsvcs/Naming/NameAcceptor.java')
-rw-r--r--java/JACE/netsvcs/Naming/NameAcceptor.java313
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;
+}
+