summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-08-24 23:12:29 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-08-24 23:12:29 +0000
commit65e8b604882f17ee2f0010b5c8e43d88b0164b3b (patch)
tree40a852488f0454f11c0cd3a584e0af16d82242f0
parentb1e6c61c9647b7ceaadfc7f35a0e88070ec80baa (diff)
downloadATCD-65e8b604882f17ee2f0010b5c8e43d88b0164b3b.tar.gz
Updated source files for netsvcs/Naming.
-rw-r--r--java/JACE/netsvcs/Naming/NameAcceptor.java313
-rw-r--r--java/JACE/netsvcs/Naming/NameHandler.java473
-rw-r--r--java/JACE/netsvcs/Naming/NameProxy.java405
-rw-r--r--java/JACE/netsvcs/Naming/NameReply.java169
-rw-r--r--java/JACE/netsvcs/Naming/NameRequest.java373
-rw-r--r--java/JACE/netsvcs/Naming/c.bat2
-rw-r--r--java/JACE/netsvcs/Naming/package.html11
7 files changed, 1746 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;
+}
+
diff --git a/java/JACE/netsvcs/Naming/NameHandler.java b/java/JACE/netsvcs/Naming/NameHandler.java
new file mode 100644
index 00000000000..9989e925543
--- /dev/null
+++ b/java/JACE/netsvcs/Naming/NameHandler.java
@@ -0,0 +1,473 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameHandler.java
+ *
+ *************************************************/
+package JACE.netsvcs.Naming;
+
+import java.net.SocketException;
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.SOCK_SAP.*;
+import JACE.netsvcs.Handler;
+
+/**
+ * Handlers interaction between a client (NameProxy) and the naming
+ * service database. Created by NameAcceptor to handle requests.
+ * <P>
+ * In general, the user binds a name to a (value, type) pair. The type is just
+ * treated as just another String (in the C++ version the name and value are
+ * arrays of 16 bit data types and the type is an array of 8 bit chars).
+ * <P>
+ * For this to work in the hash table scheme, the type and value are wrapped in
+ * a ValueType class defined as a nested top level class within the
+ * NameHandler.
+ * <P>
+ * This is compatible with the C++ ACE remote name service.
+ *
+ *@see JACE.netsvcs.Naming.NameAcceptor
+ *@see JACE.netsvcs.Naming.NameRequest
+ *@see JACE.netsvcs.Naming.NameReply
+ *
+ *@author Everett Anderson
+ */
+public class NameHandler extends Handler
+{
+ /**
+ * Constructor
+ *
+ * @param mapping Hash table created in NameAcceptor
+ */
+ public NameHandler (Hashtable mapping)
+ {
+ this.mapping_ = mapping;
+ }
+
+ /**
+ * Read in the given NameRequest and calls dispatch.
+ */
+ public void processRequest (Object request)
+ throws SocketException, EOFException, IOException
+ {
+ NameRequest nameRequest = (NameRequest)request;
+
+ nameRequest.streamInFrom (peer ().dataInputStream ());
+
+ this.dispatch (nameRequest);
+ }
+
+ /**
+ * Create a new instance of NameRequest.
+ */
+ public Object newRequest ()
+ {
+ return new NameRequest ();
+ }
+
+ /**
+ * This is the point at which a request is sent to the various methods
+ * that fulfill it. It switches on the request type -- bind,
+ * rebind, resolve, etc.
+ *
+ *@param nameRequest The request to respond to
+ */
+ void dispatch (NameRequest nameRequest) throws IOException
+ {
+ NameAcceptor parent = (NameAcceptor)parent ();
+
+ // Call the various other member functions based on the
+ // message type of the request -- bind, rebind, etc.
+ switch (nameRequest.requestType())
+ {
+ case NameRequest.BIND:
+ this.bind(nameRequest, false);
+ parent.modifiedMapping (true);
+ break;
+ case NameRequest.REBIND:
+ this.bind(nameRequest, true);
+ parent.modifiedMapping (true);
+ break;
+ case NameRequest.RESOLVE:
+ this.resolve(nameRequest);
+ break;
+ case NameRequest.UNBIND:
+ this.unbind(nameRequest);
+ parent.modifiedMapping (true);
+ break;
+ case NameRequest.LIST_NAMES:
+ this.listByName(nameRequest.name(), false);
+ break;
+ case NameRequest.LIST_VALUES:
+ this.listByValue(nameRequest.name(), false);
+ break;
+ case NameRequest.LIST_TYPES:
+ this.listByType(nameRequest.name(), false);
+ break;
+ case NameRequest.LIST_NAME_ENTRIES:
+ this.listByName(nameRequest.name(), true);
+ break;
+ case NameRequest.LIST_VALUE_ENTRIES:
+ this.listByValue(nameRequest.name(), true);
+ break;
+ case NameRequest.LIST_TYPE_ENTRIES:
+ this.listByType(nameRequest.name(), true);
+ break;
+ default:
+ ACE.ERROR("Unknown type: " + nameRequest.requestType());
+
+ // Send a failure message. This will only work if the other
+ // side is expecting something like a NameReply rather than
+ // a NameRequest. It would've been better to have everything
+ // use NameRequests to avoid this kind of thing.
+ NameReply reply = new NameReply (NameReply.FAILURE, 0);
+ reply.streamOutTo(peer ().dataOutputStream ());
+ break;
+ }
+
+ }
+
+ /**
+ *
+ * Bind a name and a (value, type) pair. All this data is given in the
+ * NameRequest from the client. Returns a NameReply back to the client
+ * with either Reply.SUCCESS or Reply.FAILURE as the type.
+ *
+ *@param request NameRequest given by the client
+ *@param rebind Is this a rebind or not?
+ */
+ void bind (NameRequest request,
+ boolean rebind) throws IOException
+ {
+ // The hash table entries consists of (String name, ValueType data)
+ // pairs, so create the appropriate ValueType
+ ValueType vt = new ValueType(request.type(),
+ request.value());
+
+ // Reply to tell sender of success or failure
+ NameReply reply = new NameReply();
+
+ // If it's a rebind request, overwrite the old entry. If the key doesn't
+ // exist, add it. If it does exist and it's not a bind request, return
+ // a failure code via a NameReply.
+ if ((rebind) || (!this.mapping_.containsKey(request.name()))) {
+
+ ACE.DEBUG ("Binding: " + request.name() + " and " + vt.value_);
+
+ // Add/Update the entry in the hash table
+ this.mapping_.put(request.name(), vt);
+
+ // Set the reply code to success
+ reply.type(NameReply.SUCCESS);
+
+ } else {
+
+ ACE.DEBUG ("Key " + request.name() + " already exists");
+
+ // Set reply code to failure
+ reply.type(NameReply.FAILURE);
+
+ // reply error code unused as far as I know
+ }
+
+ reply.streamOutTo(peer ().dataOutputStream ());
+ }
+
+ /**
+ * Given a name, this looks up and returns the type and value. This is
+ * done by sending back a full NameRequest with the correct info. If
+ * there is a problem, an "empty" NameRequest is returned -- it has no
+ * name, type, or value fields.
+ *
+ *@param request NameRequest sent by the client (has the name to lookup)
+ */
+ void resolve (NameRequest request) throws IOException
+ {
+ // A NameRequest is also used in response
+ NameRequest result;
+
+ // If the requested name is in the hash table, return the data
+ if (this.mapping_.containsKey(request.name())) {
+
+ // Get the data pair based on the name
+ ValueType vt = (ValueType)this.mapping_.get(request.name());
+
+ ACE.DEBUG("Good resolve: " + vt.value_);
+
+ // Fill the reply structure
+ result = new NameRequest(NameRequest.RESOLVE,
+ null,
+ vt.value_,
+ vt.type_,
+ null);
+
+ } else {
+
+ // Otherwise return a null response
+ result = new NameRequest(NameRequest.RESOLVE,
+ null,
+ null,
+ null,
+ null);
+
+ }
+
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+
+ /**
+ *
+ * Given a name, remove its entry in the mapping. Returns a NameReply
+ * to the client with NameReply.SUCCESS or NameReply.FAILURE.
+ *
+ *@param request NameRequest from the client (has the name to remove)
+ */
+ void unbind (NameRequest request) throws IOException
+ {
+ NameReply reply = new NameReply();
+
+ // If the given key isn't in the table, return an error
+ // Otherwise remove it. Uses a NameReply to respond.
+ if (!this.mapping_.containsKey(request.name()))
+ reply.type(NameReply.FAILURE);
+ else {
+ this.mapping_.remove(request.name());
+ reply.type(NameReply.SUCCESS);
+ }
+
+ // Send the reply out to the socket
+ reply.streamOutTo (peer ().dataOutputStream ());
+ }
+
+ /**
+ *
+ * Given a pattern string (given in NameRequest's name field), this
+ * finds all the entries in the mapping which have a name that begins with
+ * the string. Each one is sent back separately via a NameRequest, and this
+ * sequence is followed by a blank NameRequest.
+ *
+ *@param pattern Pattern to find (what result names should
+ * begin with)
+ *@param completeLookup Should the value and type be returned as well?
+ */
+ void listByName (String pattern,
+ boolean completeLookup) throws IOException
+ {
+ // Get a listing of all the keys in the hash table
+ Enumeration enum = this.mapping_.keys();
+
+ // References used in the loop
+ String name;
+ ValueType vt;
+
+ // A NameRequest is used to return each item corresponding to the pattern.
+ NameRequest result =
+ new NameRequest((completeLookup ? NameRequest.LIST_NAMES :
+ NameRequest.LIST_NAME_ENTRIES),
+ null,
+ null,
+ null,
+ null);
+
+ // Keep ourselves safe from null pointer exceptions
+ if (pattern == null)
+ pattern = new String("");
+
+ // Scan through all the elements
+ while (enum.hasMoreElements()) {
+
+ // Get a key
+ name = (String)enum.nextElement();
+
+ // Does it fit the pattern?
+ if (name.startsWith(pattern)) {
+
+ // Set the result name
+ result.name(name);
+
+ // Only make another hash table request if the user
+ // wants all the data
+ if (completeLookup) {
+
+ // Get data from the hash table
+ vt = (ValueType)mapping_.get(name);
+
+ // Set the rest of the data
+ result.type(vt.type_);
+ result.value(vt.value_);
+ }
+
+ // Send it to the socket
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+ }
+
+ // Send final null message
+ result.name(null);
+ result.type(null);
+ result.value(null);
+ result.requestType(NameRequest.MAX_ENUM);
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+
+ /**
+ *
+ * Given a pattern string (given in NameRequest's name field), this
+ * finds all the entries in the mapping which have a type that begins with
+ * the string. Each one is sent back separately via a NameRequest, and this
+ * sequence is followed by a blank NameRequest.
+ *
+ *@param pattern Pattern to find (what result types should
+ * begin with)
+ *@param completeLookup Should the value be returned as well? This is
+ * only used to decide between LIST_TYPES and
+ * LIST_TYPE_ENTRIES since we might as well send
+ * back both if we look them up together.
+ */
+ void listByType (String pattern,
+ boolean completeLookup) throws IOException
+ {
+ // Get a listing of all the keys in the hash table
+ Enumeration enum = this.mapping_.keys();
+
+ // References used in the loop
+ String name;
+ ValueType vt;
+
+ // A NameRequest is used to return each item corresponding to the pattern.
+ NameRequest result =
+ new NameRequest((completeLookup ? NameRequest.LIST_TYPES :
+ NameRequest.LIST_TYPE_ENTRIES),
+ null,
+ null,
+ null,
+ null);
+ // Keep ourselves safe from null pointer exceptions
+ if (pattern == null)
+ pattern = new String("");
+
+ // Scan through all the elements
+ while (enum.hasMoreElements()) {
+
+ // Get a key
+ name = (String)enum.nextElement();
+
+ // Have to get all the data for this entry to compare
+ vt = (ValueType)mapping_.get(name);
+
+ // Does it fit the pattern?
+ if (vt.type_ != null)
+ if (vt.type_.startsWith(pattern)) {
+
+ // Set the result values
+ result.name(name);
+ result.type(vt.type_);
+ result.value(vt.value_);
+
+ // Send it out to the socket
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+ }
+
+ // Send final null message
+ result.name(null);
+ result.type(null);
+ result.value(null);
+ result.requestType(NameRequest.MAX_ENUM);
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+ /**
+ *
+ * Given a pattern string (given in NameRequest's name field), this
+ * finds all the entries in the mapping which have a value that begins with
+ * the string. Each one is sent back separately via a NameRequest, and this
+ * sequence is followed by a blank NameRequest.
+ *
+ *@param pattern Pattern to find (what result values should
+ * begin with)
+ *@param completeLookup Should the value be returned as well? This is
+ * only used to decide between LIST_TYPES and
+ * LIST_TYPE_ENTRIES since we might as well send
+ * back both if we look them up together.
+ */
+ void listByValue (String pattern,
+ boolean completeLookup) throws IOException
+ {
+ // Get a listing of all the keys in the hash table
+ Enumeration enum = this.mapping_.keys();
+
+ // References used in the loop
+ String name;
+ ValueType vt;
+
+ // A NameRequest is used to return each item corresponding to the pattern.
+ NameRequest result =
+ new NameRequest((completeLookup ? NameRequest.LIST_VALUES :
+ NameRequest.LIST_VALUE_ENTRIES),
+ null,
+ null,
+ null,
+ null);
+ // Keep ourselves safe from null pointer exceptions
+ if (pattern == null)
+ pattern = new String("");
+
+ // Scan through all the elements
+ while (enum.hasMoreElements()) {
+
+ // Get a key
+ name = (String)enum.nextElement();
+
+ // Have to get all the data for this entry to compare
+ vt = (ValueType)mapping_.get(name);
+
+ // Does it fit the pattern?
+ if (vt.value_ != null)
+ if (vt.value_.startsWith(pattern)) {
+
+ // Set the result values
+ result.name(name);
+ result.type(vt.type_);
+ result.value(vt.value_);
+
+ // Send it out to the socket
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+ }
+
+ // Send final null message
+ result.name(null);
+ result.type(null);
+ result.value(null);
+ result.requestType(NameRequest.MAX_ENUM);
+ result.streamOutTo (peer ().dataOutputStream ());
+ }
+
+ // References to the hash table and the timer queue
+ private Hashtable mapping_;
+
+ /**
+ * A simple wrapper to keep the type and value together in
+ * the hash table.
+ */
+ static class ValueType implements Serializable
+ {
+ /**
+ * Constructor
+ *
+ *@param type Type string to include
+ *@param value Value string to include
+ */
+ ValueType(String type, String value)
+ { this.type_ = type; this.value_ = value; }
+
+ public String type_;
+ public String value_;
+ }
+}
diff --git a/java/JACE/netsvcs/Naming/NameProxy.java b/java/JACE/netsvcs/Naming/NameProxy.java
new file mode 100644
index 00000000000..9b1b3102f1d
--- /dev/null
+++ b/java/JACE/netsvcs/Naming/NameProxy.java
@@ -0,0 +1,405 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameProxy.java
+ *
+ *************************************************/
+package JACE.netsvcs.Naming;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.SOCK_SAP.*;
+import JACE.Connection.*;
+
+/**
+ * Proxy which clients can use to interact with the naming service.
+ * Can be used with the Connector.
+ *
+ *@see JACE.Connection.Connector
+ *@see NameAcceptor
+ *@see NameHandler
+ *
+ *@author Everett Anderson
+ */
+public class NameProxy extends SvcHandler
+{
+ /**
+ * Constructor, connects itself using a Connector.
+ *
+ *@param host name of the host of the naming service
+ *@param port port to connect to on the host
+ */
+ public NameProxy (String host, int port)
+ throws UnknownHostException,
+ SocketException,
+ InstantiationException,
+ IllegalAccessException,
+ IOException
+ {
+ Connector c = new Connector ();
+ c.open (host, port);
+ c.connect (this);
+ }
+
+ /**
+ * Default constructor. Proxies created with this constructor must
+ * be connected to use.
+ */
+ public NameProxy ()
+ {
+ }
+
+ /**
+ * Constructor taking a SOCKStream to use.
+ *
+ *@param sock SOCKStream already open to the naming service
+ */
+ public NameProxy (SOCKStream sock)
+ {
+ this.stream_ = sock;
+ }
+
+ /**
+ * Initialize this proxy. (Called by Connector)
+ */
+ public int open (Object obj)
+ {
+ connected_ = true;
+ return 0;
+ }
+
+ /**
+ * Close the proxy, shutting down the connection to the service.
+ */
+ public int close ()
+ {
+ if (!connected_)
+ return 0;
+
+ try {
+ this.peer ().close ();
+ } catch (IOException e) {
+ return -1;
+ } finally {
+ connected_ = false;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Attempt to bind the given data pair
+ * @param name Name/key
+ * @param value Value to bind
+ *
+ * @return True iff bind is successful
+ */
+ public boolean bind(String name, String value) throws IOException
+ {
+ return this.bind(name, value, null, false);
+ }
+
+ /**
+ * Attempt to bind the given data triplet
+ * @param name Name/key
+ * @param value Value to bind
+ * @param type Type to bind (another string)
+ *
+ * @return True iff the bind was successful
+ */
+ public boolean bind(String name, String value, String type)
+ throws IOException
+ {
+ return this.bind(name, value, type, false);
+ }
+
+ /**
+ * The most generic of the bind methods. Allows factoring out of
+ * common code. Not public.
+ */
+ boolean bind (String name, String value, String type, boolean rebind)
+ throws IOException
+ {
+ // Create a new NameRequest with the desired info
+ NameRequest request =
+ new NameRequest(rebind ? NameRequest.REBIND : NameRequest.BIND,
+ name,
+ value,
+ type,
+ null);
+
+ // Send it to the naming service
+ request.streamOutTo(this.stream_);
+
+ // Create a reply
+ NameReply reply = new NameReply();
+
+ // Get the status of the bind from the naming service
+ reply.streamInFrom(this.stream_);
+
+ // Return true on success
+ return (reply.type() == NameReply.SUCCESS ? true : false);
+ }
+
+ /**
+ * Rebind a name and a value
+ * @param name Name/key
+ * @param value Bound value
+ *
+ * @return True if the rebind was successful
+ */
+ public boolean rebind (String name, String value) throws IOException
+ {
+ return this.bind(name, value, null, true);
+ }
+
+ /**
+ * Rebind a name, value, and type
+ * @param name Name/key
+ * @param value Bound value
+ * @param type Bound type
+ *
+ * @return True if rebind was successful
+ */
+ public boolean rebind (String name, String value, String type)
+ throws IOException
+ {
+ return this.bind(name, value, type, true);
+ }
+ /**
+ * Look up information bound to the given key/name.
+ *
+ * @param name Name/key
+ *
+ * @return Vector with three elements:
+ * 0 Name/key
+ * 1 Value
+ * 2 Type
+ */
+ public Vector resolve (String name) throws IOException
+ {
+ // Create a new NameRequest with the name & request type
+ NameRequest request = new NameRequest(NameRequest.RESOLVE,
+ name,
+ null,
+ null,
+ null);
+
+ // Send it to the naming service
+ request.streamOutTo(this.stream_);
+
+ // Get a response (hopefully with the value and type)
+ request.streamInFrom(this.stream_);
+
+ // Dump the result into a vector
+ Vector result = new Vector();
+
+ result.addElement(request.name());
+ result.addElement(request.value());
+ result.addElement(request.type());
+
+ // Cut it down to the size we need
+ result.trimToSize();
+
+ return result;
+ }
+
+ /**
+ * Remove the entry in the mapping corresponding to the given name/key.
+ *
+ * @param name Name/key
+ *
+ * @return True if the unbind was successful
+ */
+ public boolean unbind (String name) throws IOException
+ {
+ NameRequest request = new NameRequest(NameRequest.UNBIND,
+ name,
+ null,
+ null,
+ null);
+ // Send the request to the naming service
+ request.streamOutTo(this.stream_);
+
+ NameReply reply = new NameReply();
+
+ // Get reply
+ reply.streamInFrom(this.stream_);
+
+ return (reply.type() == NameReply.SUCCESS ? true : false);
+ }
+
+ /**
+ * Return a vector that's a list of names (Strings) that begin with
+ * the given pattern
+ * @param pattern Search pattern
+ * @return Vector List of names
+ */
+ public Vector listNames (String pattern) throws IOException
+ {
+ return this.requestSimpleList(pattern, NameRequest.LIST_NAMES);
+ }
+
+ /**
+ * Return a vector that's a list of types (Strings) that begin with
+ * the given pattern
+ * @param pattern Search pattern
+ * @return Vector List of types
+ */
+ public Vector listTypes (String pattern) throws IOException
+ {
+ return this.requestSimpleList(pattern, NameRequest.LIST_TYPES);
+ }
+
+ /**
+ * Return a vector that's a list of values (Strings) that begin with
+ * the given pattern
+ * @param pattern Search pattern
+ * @return Vector List of values
+ */
+ public Vector listValues (String pattern) throws IOException
+ {
+ return this.requestSimpleList(pattern, NameRequest.LIST_VALUES);
+ }
+
+ /**
+ * Non-public generic list gathering method
+ */
+ Vector requestSimpleList (String pattern, int type) throws IOException
+ {
+ // Make request for a list of the given type
+ NameRequest request = new NameRequest(type,
+ pattern,
+ null,
+ null,
+ null);
+ request.streamOutTo(this.stream_);
+
+ // Allocate and reuse the DIS here rather than each time we call
+ // streamInFrom
+ DataInputStream dis = new DataInputStream(this.stream_.inputStream());
+
+ request.streamInFrom(dis);
+ Vector result = new Vector();
+
+ // Add elements until there's a null message with the MAX_ENUM
+ // request type
+ while (request.requestType() != NameRequest.MAX_ENUM) {
+ if (type == NameRequest.LIST_NAMES)
+ result.addElement(new String(request.name()));
+ else
+ if (type == NameRequest.LIST_VALUES)
+ result.addElement(new String(request.value()));
+ else
+ result.addElement(new String(request.type()));
+
+ request.streamInFrom(dis);
+ }
+
+ // Adjust the vector to the minimal size
+ result.trimToSize();
+
+ return result;
+ }
+
+ /**
+ * Get a vector with the entire data set for entries whose name begins with
+ * the given pattern. Each element in the vector is another vector
+ * with the following layout:
+ * 0 Name/key
+ * 1 Value
+ * 2 Type
+ *
+ * @param pattern Search pattern
+ * @return Vector of vectors
+ */
+ public Vector listNameEntries (String pattern) throws IOException
+ {
+ return this.requestComplexList(pattern, NameRequest.LIST_NAME_ENTRIES);
+ }
+
+ /**
+ * Get a vector with the entire data set for entries whose value begins with
+ * the given pattern. Each element in the vector is another vector
+ * with the following layout:
+ * 0 Name/key
+ * 1 Value
+ * 2 Type
+ *
+ * @param pattern Search pattern
+ * @return Vector of vectors
+ */
+ public Vector listValueEntries (String pattern) throws IOException
+ {
+ return this.requestComplexList(pattern, NameRequest.LIST_VALUE_ENTRIES);
+ }
+
+ /**
+ * Get a vector with the entire data set for entries whose type begins with
+ * the given pattern. Each element in the vector is another vector
+ * with the following layout:
+ * 0 Name/key
+ * 1 Value
+ * 2 Type
+ *
+ * @param pattern Search pattern
+ * @return Vector of vectors
+ */
+
+ public Vector listTypeEntries (String pattern) throws IOException
+ {
+ return this.requestComplexList(pattern, NameRequest.LIST_TYPE_ENTRIES);
+ }
+
+ /**
+ * Non-public generic method for getting a a vector of vectors with the
+ * entire data set for entries fitting the given pattern.
+ */
+ Vector requestComplexList (String pattern, int type) throws IOException
+ {
+ // Create request with desired type
+ NameRequest request = new NameRequest(type,
+ pattern,
+ null,
+ null,
+ null);
+ // Send it to the naming service
+ request.streamOutTo(this.stream_);
+
+ // Allocate the DIS here and reuse
+ DataInputStream dis = new DataInputStream(this.stream_.inputStream());
+
+ // Get the first response
+ request.streamInFrom(dis);
+ Vector result = new Vector();
+
+ // Loop while we don't see a null response with the MAX_ENUM
+ //request type
+ while (request.requestType() != NameRequest.MAX_ENUM) {
+ Vector entry = new Vector();
+
+ // Create an element in the main vector
+ entry.addElement(request.name());
+ entry.addElement(request.value());
+ entry.addElement(request.type());
+ entry.trimToSize();
+
+ // Add it to the result
+ result.addElement(entry);
+
+ // Get another NameRequest
+ request.streamInFrom(dis);
+ }
+
+ result.trimToSize();
+
+ return result;
+ }
+
+ private boolean connected_ = false;
+}
diff --git a/java/JACE/netsvcs/Naming/NameReply.java b/java/JACE/netsvcs/Naming/NameReply.java
new file mode 100644
index 00000000000..d20c9ed05f0
--- /dev/null
+++ b/java/JACE/netsvcs/Naming/NameReply.java
@@ -0,0 +1,169 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameReply.java
+ *
+ *************************************************/
+package JACE.netsvcs.Naming;
+
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.ASX.*;
+import JACE.SOCK_SAP.*;
+
+/**
+ * Used by the naming server to give quick status messages
+ * to the client. This is only used to signal the success or
+ * failure of bind and unbind requests. The error number seems
+ * to be unused in the C++ version.
+ *
+ *@see NameHandler
+ *@author Everett Anderson
+ *
+ */
+public class NameReply
+{
+ /** Successful operation indicator */
+ public final static int SUCCESS = 0;
+
+ /** Failed operation indicator */
+ public final static int FAILURE = -1;
+
+ /**
+ * Default Constructor (success, errno 0)
+ */
+ public NameReply ()
+ {
+ this.type_ = this.SUCCESS;
+ this.errno_ = 0;
+ }
+
+ /**
+ * Constructor
+ *
+ *@param type Success or failure
+ *@param err Error number (unused)
+ */
+ public NameReply (int type, int err)
+ {
+ this.type_ = type;
+ this.errno_ = err;
+ }
+
+ /**
+ * Length accessor
+ */
+ int length()
+ { return this.length_; }
+
+ /**
+ * Type accessor -- success or failure
+ */
+ int type()
+ { return this.type_; }
+
+ /**
+ * Error number accessor
+ */
+ int errno()
+ { return this.errno_; }
+
+ /**
+ * Set type
+ * @param type New type
+ */
+ void type(int type)
+ { this.type_ = type; }
+
+ /**
+ * Set error number
+ * @param errno New error number
+ */
+ void errno(int errno)
+ { this.errno_ = errno; }
+
+ /**
+ * Send this data to the given SOCKStream.
+ *
+ *@param sock SOCKStream to send to
+ */
+ public void streamOutTo (JACE.SOCK_SAP.SOCKStream sock) throws IOException
+ {
+ streamOutTo (sock.dataOutputStream ());
+ }
+
+ /**
+ * Send this instance to the given DataOutputStream.
+ */
+ public void streamOutTo (DataOutputStream dos) throws IOException
+ {
+ dos.writeInt(this.length_);
+ dos.writeInt(this.type_);
+ dos.writeInt(this.errno_);
+
+ dos.flush();
+ }
+
+ /**
+ * Send this instance to the given OutputStream.
+ */
+ public void streamOutTo (OutputStream os) throws IOException
+ {
+ BufferedOutputStream bos = new BufferedOutputStream (os);
+ DataOutputStream dos = new DataOutputStream (bos);
+
+ streamOutTo (dos);
+ }
+
+ /**
+ * Fill the fields of this instance from data in the socket
+ *
+ *@param sock SOCKStream to read from
+ */
+ public void streamInFrom (JACE.SOCK_SAP.SOCKStream sock) throws IOException
+ {
+ this.streamInFrom(sock.dataInputStream ());
+ }
+
+ /**
+ * Fill this instance from the DataInputStream (which should be buffered).
+ *
+ *@param dis DataInputStream to use
+ */
+ public void streamInFrom (DataInputStream dis) throws IOException
+ {
+ int length = dis.readInt();
+
+ if (length != this.length_)
+ throw new IOException("Incorrect NameReply length");
+
+ type_ = dis.readInt();
+ errno_ = dis.readInt();
+ }
+
+ /**
+ * Fill this instance from the given InputStream.
+ */
+ public void streamInFrom (InputStream is) throws IOException
+ {
+ BufferedInputStream bis = new BufferedInputStream (is);
+ DataInputStream dis = new DataInputStream (bis);
+
+ streamInFrom (dis);
+ }
+
+ final static int length_ = 12;
+
+ int type_;
+ int errno_;
+}
+
+
+
+
diff --git a/java/JACE/netsvcs/Naming/NameRequest.java b/java/JACE/netsvcs/Naming/NameRequest.java
new file mode 100644
index 00000000000..706b14728c5
--- /dev/null
+++ b/java/JACE/netsvcs/Naming/NameRequest.java
@@ -0,0 +1,373 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameRequest.java
+ *
+ *@see netsvcs.Naming.NameHandler
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.netsvcs.Naming;
+
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.ASX.*;
+import JACE.SOCK_SAP.*;
+
+/**
+ * Holds information including name, value, type, and request
+ * type. Used by both client and naming server as detailed in
+ * NameHandler. Compatible with the C++ ACE_Name_Request.
+ *
+ *@see NameHandler
+ */
+public class NameRequest
+{
+ /** Bind request type */
+ public static final int BIND = 1;
+
+ /** Rebind request type */
+ public static final int REBIND = 2;
+
+ /** Resolve request type */
+ public static final int RESOLVE = 3;
+
+ /** Unbind request type */
+ public static final int UNBIND = 4;
+
+ /** List Names request type */
+ public static final int LIST_NAMES = 5;
+
+ /** List Values request type */
+ public static final int LIST_VALUES = 13;
+
+ /** List Types request type */
+ public static final int LIST_TYPES = 21;
+
+ /** List Name Entries request type */
+ public static final int LIST_NAME_ENTRIES = 6;
+
+ /** List Value Entries request type */
+ public static final int LIST_VALUE_ENTRIES = 14;
+
+ /** List Type Entries request type */
+ public static final int LIST_TYPE_ENTRIES = 22;
+
+ /** Type used to send a final "null" request when returning
+ * a list of items */
+ public static final int MAX_ENUM = 11;
+ /**
+ * Maximum length of a NameRequest instance.
+ * See C++ ACE Name_Request_Reply.h for the details of the
+ * value of this constant.
+ */
+ public static final int MAX_LEN = 6182;
+
+ /**
+ * Default constructor.
+ */
+ public NameRequest ()
+ {
+ this.name_ = this.value_ = this.type_ = null;
+ this.length_ = 32;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param requestType Type of request this is (BIND, REBIND, etc)
+ * @param name Key to bind
+ * @param value Value to bind
+ * @param type Type to couple with the value
+ * @param timeout Timer information (not really used in JACE yet)
+ */
+ public NameRequest(int requestType,
+ String name,
+ String value,
+ String type,
+ TimeValue timeout)
+ {
+ this.requestType_ = requestType;
+
+ if (timeout == null) {
+
+ this.blockForever_ = 1;
+ this.secTimeout_ = 0;
+ this.usecTimeout_ = 0;
+ } else {
+
+ this.blockForever_ = 0;
+ this.secTimeout_ = (int)timeout.sec();
+ this.usecTimeout_ = (int)timeout.getMilliTime() * 1000;
+ }
+
+ // This is necessary to make sure null pointer exceptions are
+ // avoided. It makes it more consistent later on
+ if (name == null)
+ this.name_ = new String("");
+ else
+ this.name_ = new String(name);
+ if (value == null)
+ this.value_ = new String("");
+ else
+ this.value_ = new String(value);
+ if (type == null)
+ this.type_ = new String("");
+ else
+ this.type_ = new String(type);
+
+ // Set the length
+ this.calculateLength();
+ }
+
+ /**
+ * Calculate the transmission length (bytes) of this structure
+ */
+ private void calculateLength()
+ {
+ // The type is sent as an 8 bit data type (chars in the C++ version),
+ // but the name and value are sent as 16 bit chars (ACE_USHORT16's in C++)
+
+ this.length_ = 34 + this.type_.length() + 2 * (this.name_.length() +
+ this.value_.length());
+ }
+
+ /**
+ * Return the transmission length
+ */
+ public int length()
+ { return this.length_; }
+
+ /**
+ * Return the name/key
+ */
+ public String name()
+ { return new String(this.name_); }
+
+ /**
+ * Set the name/key
+ * @param name Name to set to
+ */
+ public void name(String name)
+ {
+ if (name == null)
+ this.name_ = new String("");
+ else
+ this.name_ = new String(name);
+
+ this.calculateLength();
+ }
+
+ /**
+ * Return the value
+ */
+ public String value()
+ { return new String(this.value_); }
+
+ /**
+ * Set the value
+ * @param value New value
+ */
+ public void value(String value)
+ {
+ if (value == null)
+ this.value_ = new String("");
+ else
+ this.value_ = new String(value);
+
+ this.calculateLength();
+ }
+
+ /**
+ * Return the type
+ */
+ public String type()
+ { return new String(this.type_); }
+
+ /**
+ * Set the type
+ * @param type New type
+ */
+ public void type(String type)
+ {
+ if (type == null)
+ this.type_ = new String("");
+ else
+ this.type_ = new String(type);
+
+ this.calculateLength();
+ }
+
+ /**
+ * Fill the fields of this instance with data from the InputStream.
+ */
+ public void streamInFrom (InputStream is) throws IOException
+ {
+ BufferedInputStream bis = new BufferedInputStream (is);
+
+ DataInputStream dis = new DataInputStream (bis);
+
+ this.streamInFrom(dis);
+ }
+
+ /**
+ * Fill the fields of this instance with data from the SOCKStream.
+ */
+ public void streamInFrom (SOCKStream sock) throws IOException
+ {
+ streamInFrom (sock.dataInputStream ());
+ }
+
+ /**
+ * Fill the fields of this instance from the given DataInputStream
+ *
+ *@param dis DataInputStream to read from
+ */
+ public void streamInFrom (DataInputStream dis) throws IOException
+ {
+ // Read the length (32 bits)
+ length_ = dis.readInt();
+
+ if (length_ > MAX_LEN)
+ throw new IOException ("Invalid NameRequest length " + length_);
+
+ // Read the request type
+ requestType_ = dis.readInt();
+
+ // Can we block forever to fulfill this request? (unused)
+ blockForever_ = dis.readInt();
+
+ // How long until we should time out this request? (unused)
+ secTimeout_ = dis.readInt();
+ usecTimeout_ = dis.readInt();
+
+ // The sizes are in bytes, and there are two bytes per char
+ // (ACE_USHORT16 in C++ land)
+ int nameLen = dis.readInt() / 2;
+ int valueLen = dis.readInt() / 2;
+
+ int typeLen = dis.readInt();
+
+ // Read the name -- just read chars since they're 16 bits.
+ // Hopefully the SOCKStream has buffered the data
+ char buf[] = new char[nameLen];
+ for (int i = 0; i < nameLen; i++) {
+ buf[i] = dis.readChar();
+ }
+ this.name_ = new String(buf);
+
+ // Read the value
+ buf = new char[valueLen];
+ for (int i = 0; i < valueLen; i++)
+ buf[i] = dis.readChar();
+ this.value_ = new String(buf);
+
+ // Read the type -- now we can use readFully since
+ // the type was sent as 8 bit chars
+ byte tbuf[] = new byte[typeLen];
+ dis.readFully(tbuf);
+ this.type_ = new String(tbuf);
+
+ // Skip the null char at the end
+ dis.skipBytes(2);
+ }
+
+ /**
+ * Write the data of this instance to the given SOCKStream.
+ */
+ public void streamOutTo (SOCKStream sock) throws IOException
+ {
+ streamOutTo (sock.dataOutputStream ());
+ }
+
+ /**
+ * Write the data of this instance to the given OutputStream.
+ */
+ public void streamOutTo (OutputStream os) throws IOException
+ {
+ BufferedOutputStream bos = new BufferedOutputStream (os);
+ DataOutputStream dos = new DataOutputStream (bos);
+
+ streamOutTo (dos);
+ }
+
+ /**
+ * Send this NameRequest out to the given DataOutputStream
+ */
+ public void streamOutTo (DataOutputStream dos) throws IOException
+ {
+ dos.writeInt(length_);
+ dos.writeInt(requestType_);
+ dos.writeInt(blockForever_);
+ dos.writeInt(secTimeout_);
+ dos.writeInt(usecTimeout_);
+
+ // Byte sizes are sent, and the name and value are stored as
+ // 16 bit char arrays (ACE_USHORT16 arrays in C++ version)
+ dos.writeInt(this.name_.length() * 2);
+ dos.writeInt(this.value_.length() * 2);
+ dos.writeInt(this.type_.length());
+
+ // Making sure the name_ wasn't null comes in handy
+ // in situations like this
+ dos.writeChars(this.name_);
+ dos.writeChars(this.value_);
+ dos.writeBytes(this.type_);
+
+ // Null termination
+ dos.writeChar(0);
+
+ // Send it for real
+ dos.flush();
+ }
+
+ /**
+ * Set the requestType
+ *@param type Type to set to
+ */
+ public void requestType(int type)
+ {
+ this.requestType_ = type;
+ }
+
+ /**
+ * Get requestType
+ */
+ public int requestType()
+ {
+ return this.requestType_;
+ }
+
+ /**
+ * Can we block forever to fulfill the request? (unused)
+ */
+ public boolean blockForever()
+ {
+ return (this.blockForever_ != 0) ? true : false;
+ }
+
+ /**
+ * Allowed timeout (unused)
+ */
+ public int secTimeout()
+ {
+ return this.secTimeout_;
+ }
+
+ int length_;
+ int requestType_;
+ int blockForever_;
+ int secTimeout_;
+ int usecTimeout_;
+
+ String name_;
+ String value_;
+ String type_;
+};
diff --git a/java/JACE/netsvcs/Naming/c.bat b/java/JACE/netsvcs/Naming/c.bat
new file mode 100644
index 00000000000..2b540b1b051
--- /dev/null
+++ b/java/JACE/netsvcs/Naming/c.bat
@@ -0,0 +1,2 @@
+@echo off
+javac -d c:\Everett\JACE\classes *.java
diff --git a/java/JACE/netsvcs/Naming/package.html b/java/JACE/netsvcs/Naming/package.html
new file mode 100644
index 00000000000..b7ee951fc2e
--- /dev/null
+++ b/java/JACE/netsvcs/Naming/package.html
@@ -0,0 +1,11 @@
+<!-- $Id$ -->
+<HTML>
+<BODY>
+Naming Service for associating names and values in a distributed system.
+<P>
+A simple test program for NameProxy and the naming service is in
+the tests directory under netsvcs\Naming.
+
+@see <a href="http://www.cs.wustl.edu/~schmidt/ACE-netsvcs.html">ACE Network Services</a>
+</BODY>
+</HTML>