summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-05-12 19:59:44 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-05-12 19:59:44 +0000
commit2fa8a8d25159c89e0ce4db26dc8b187b01236f41 (patch)
treec6bf6b5402b999b722c11b83cc28fd63ff414379 /java
parentea2e1d76a4f50a3e99fdd4978be57fdecf5711d8 (diff)
downloadATCD-2fa8a8d25159c89e0ce4db26dc8b187b01236f41.tar.gz
Added the Naming service to the repository (again?). There may be a problem
since this has always been in the release archives, but somehow didn't stick in CVS.
Diffstat (limited to 'java')
-rw-r--r--java/netsvcs/Naming/Makefile24
-rw-r--r--java/netsvcs/Naming/NameAcceptor.java306
-rw-r--r--java/netsvcs/Naming/NameHandler.java521
-rw-r--r--java/netsvcs/Naming/NameProxy.java351
-rw-r--r--java/netsvcs/Naming/NameReply.java145
-rw-r--r--java/netsvcs/Naming/NameRequest.java331
6 files changed, 1678 insertions, 0 deletions
diff --git a/java/netsvcs/Naming/Makefile b/java/netsvcs/Naming/Makefile
new file mode 100644
index 00000000000..af49d9061d8
--- /dev/null
+++ b/java/netsvcs/Naming/Makefile
@@ -0,0 +1,24 @@
+# Makefile
+# $Id$
+
+.SUFFIXES: .java .class
+
+JACE_WRAPPER = $(WRAPPER_ROOT)/java
+
+all:
+ javac -d ${JACE_WRAPPER}/classes $(files)
+doc:
+ javadoc -d ${JACE_WRAPPER}/doc $(files) $(packages)
+
+files = NameAcceptor.java \
+ NameHandler.java \
+ NameRequest.java \
+ NameReply.java \
+ NameProxy.java \
+
+packages = netsvcs \
+ netsvcs.Naming
+
+realclean:
+ /bin/rm -rf ${JACE_WRAPPER}/classes/netsvcs/Naming
+
diff --git a/java/netsvcs/Naming/NameAcceptor.java b/java/netsvcs/Naming/NameAcceptor.java
new file mode 100644
index 00000000000..f704504ee3c
--- /dev/null
+++ b/java/netsvcs/Naming/NameAcceptor.java
@@ -0,0 +1,306 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameAcceptor.java
+ *
+ * Listens on the specified port (command line option) and launches
+ * NameHandlers when connections are made. Each NameHandler runs in
+ * its own thread.
+ *
+ * The hash table for the mapping and a timer queue are created here.
+ * Periodically the mapping is written out to a file.
+ *
+ * A small main program is included to start things off. If the
+ * data file exists, it is read into memory. Currently the service
+ * stores the entire mapping in memory at all times. The mapping is
+ * dumped to a file at regular intervals.
+ *
+ *@see netsvcs.Naming.NameHandler
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package 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;
+
+public class NameAcceptor extends Acceptor implements Runnable
+{
+ /**
+ * Constructor
+ */
+ public NameAcceptor ()
+ {
+ super();
+
+ // Create the hash table and timer queue
+ this.mapping_ = new Hashtable();
+ this.tq_ = new TimerQueue(true);
+ }
+
+ /**
+ * Simple main program. Command line options are
+ * described under parseArgs.
+ */
+ public static void main (String [] args)
+ {
+ // Simple main program to get things rolling
+ NameAcceptor na = new NameAcceptor();
+
+ na.init(args);
+ }
+
+
+ /**
+ * Close the socket when shutting down
+ */
+ public int fini ()
+ {
+ try
+ {
+ this.done_ = true;
+ this.sockAcceptor_.close();
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR("" + e);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Stops accepting when suspended
+ */
+ public int suspend()
+ {
+ this.suspended_ = true;
+ return 0;
+ }
+
+ /**
+ * Resumes accepting
+ */
+ public int resume()
+ {
+ this.suspended_ = false;
+ return 0;
+ }
+
+
+ /**
+ * Runs this instance in its own thread
+ */
+ public int init (String [] args)
+ {
+ // Parse arguments
+ this.parseArgs (args);
+
+ System.out.println("Starting naming service on port: " + this.port_);
+
+ // Run in own thread of control so that we don't block the caller
+ new Thread (this).start();
+
+ return 0;
+ }
+
+ /**
+ *
+ * Main loop: launches NameHandlers in separate threads whenever a
+ * connection request is made
+ */
+ public void run ()
+ {
+ // Load the hash table from disk
+ this.loadTable();
+
+ // Schedule to write out the memory copy of the hash table at regular
+ // intervals
+ this.tq_.scheduleTimer(this,
+ null,
+ new TimeValue(this.updateInterval_),
+ new TimeValue(this.updateInterval_));
+
+ try
+ {
+ // Create new NameHandlers as requests come in
+ this.open (this.port_);
+ while (!this.done_) {
+
+ if (!this.suspended_)
+ this.accept ();
+ }
+ }
+ catch (SocketException e)
+ {
+ ACE.ERROR ("Socket Exception: " + e);
+ }
+ catch (InstantiationException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IllegalAccessException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+ }
+
+ /**
+ * Create a new NameHandler
+ */
+ protected SvcHandler makeSvcHandler ()
+ throws InstantiationException, IllegalAccessException
+ {
+ return new netsvcs.Naming.NameHandler (this.mapping_);
+ }
+
+ /**
+ * Process the command line. The following options are available:
+ *
+ * -p <port> Port number for listening
+ * -f <filename> Name of the database file
+ * -t <time> Mapping write-out time interval (in seconds)
+ *
+ */
+ protected void parseArgs (String args[])
+ {
+ String s;
+ GetOpt opt = new GetOpt (args, "p:f:t:");
+ for (int c; (c = opt.next ()) != -1; )
+ {
+ switch (c)
+ {
+ // Specify port
+ case 'p':
+ s = opt.optarg ();
+ this.port_ = (new Integer (s)).intValue ();
+ break;
+ // Specify file name of the database
+ case 'f':
+ s = opt.optarg ();
+ this.filename_ = new String(s);
+ break;
+ // Specify time interval to write out the table
+ case 't':
+ s = opt.optarg ();
+ this.updateInterval_ = (new Integer (s)).intValue();
+ break;
+ default:
+ ACE.ERROR ("Unknown argument: " + c);
+ break;
+ }
+ }
+ }
+
+ /**
+ * 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.
+ */
+ protected void saveTable ()
+ {
+ FileOutputStream fos;
+ ObjectOutputStream oos;
+
+ try {
+
+ fos = new FileOutputStream(this.filename_);
+ oos = new ObjectOutputStream(fos);
+
+ oos.writeObject(this.mapping_);
+
+ 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;
+ }
+
+ // Port to listen on
+ private int port_ = ACE.DEFAULT_SERVER_PORT;
+
+ // 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 done_ = false;
+ boolean suspended_ = false;
+
+}
+
diff --git a/java/netsvcs/Naming/NameHandler.java b/java/netsvcs/Naming/NameHandler.java
new file mode 100644
index 00000000000..a619eab0733
--- /dev/null
+++ b/java/netsvcs/Naming/NameHandler.java
@@ -0,0 +1,521 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameHandler.java
+ *
+ * An instance of this class is created in a separate thread for each connection
+ * request received by the NameAcceptor. All interaction between the
+ * client's requests and the database are handled here.
+ *
+ * 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).
+ *
+ * For this to work in the hash table scheme, the type and value are wrapped in
+ * a ValueType class defined at the end of this file.
+ *
+ * This is compatible with the C++ ACE remote name service.
+ *
+ *@see netsvcs.Naming.NameAcceptor
+ *@see netsvcs.Naming.NameRequest
+ *@see netsvcs.Naming.NameReply
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Naming;
+
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.SOCK_SAP.*;
+
+public class NameHandler extends SvcHandler
+{
+ /**
+ * Constructor
+ *
+ * @param mapping Hash table created in NameAcceptor
+ */
+ public NameHandler (Hashtable mapping)
+ {
+ super();
+
+ this.mapping_ = mapping;
+ }
+
+ /**
+ * Starts this handler in its own thread
+ *
+ */
+ public int open (Object obj)
+ {
+ new Thread (this).start ();
+ return 0;
+ }
+
+ /**
+ * Main loop that this thread executes. Waits for connection requests and
+ * creates a NameHandler thread for each.
+ *
+ */
+ public void run ()
+ {
+ ACE.DEBUG("NameHandler instance running");
+
+ // Can't assume the SOCKStream uses DataInputStream, so put one
+ // over its OutputStream
+ DataInputStream dis = new DataInputStream (this.peer().inputStream());
+
+ // The NameRequest is the how all requests come in to the naming service.
+ NameRequest nameRequest = new NameRequest();
+
+ // Main loop -- wait for requests
+ int msgLen;
+ try
+ {
+ while (!this.done_)
+ {
+ // Read a NameRequest from the stream
+ nameRequest.streamInFrom(dis);
+
+ // Decide what to do based on the request type
+ this.dispatch(nameRequest);
+
+ }
+ }
+ catch (NullPointerException e)
+ {
+ ACE.ERROR ("Connection reset by peer");
+ }
+ catch (EOFException e)
+ {
+ /* The client has shut down the connection */
+
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+ finally
+ {
+ try
+ {
+ this.peer ().close ();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+
+ /**
+ *
+ * This is the point at which a request is sent to the various methods
+ * that fulfill it. Switches on the request type -- bind, rebind, resolve,
+ * etc.
+ *
+ *@param nameRequest The request to fill
+ */
+ void dispatch(NameRequest nameRequest) throws IOException
+ {
+
+ // 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);
+ break;
+ case NameRequest.REBIND:
+ this.bind(nameRequest, true);
+ break;
+ case NameRequest.RESOLVE:
+ this.resolve(nameRequest);
+ break;
+ case NameRequest.UNBIND:
+ this.unbind(nameRequest);
+ 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:
+ System.err.println("unknown type");
+
+ 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(this.peer());
+
+ 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()))) {
+
+ System.err.println("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(this.peer());
+ }
+
+ /**
+ * 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;
+
+ // Wrap a DataOutputStream around the socket's output stream
+ // (the socket should already have at least a BufferedOutputStream)
+ DataOutputStream dos = new DataOutputStream(this.peer().outputStream());
+
+ // 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);
+
+ }
+
+ // Send the result to the socket
+ // result.streamOutTo(dos);
+
+ result.streamOutTo(this.peer());
+
+ }
+
+ /**
+ *
+ * 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(this.peer());
+ }
+
+ /**
+ *
+ * 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(this.peer());
+ }
+ }
+
+ // Send final null message
+ result.name(null);
+ result.type(null);
+ result.value(null);
+ result.requestType(NameRequest.MAX_ENUM);
+ result.streamOutTo(this.peer());
+ }
+
+ /**
+ *
+ * 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(this.peer());
+ }
+ }
+
+ // Send final null message
+ result.name(null);
+ result.type(null);
+ result.value(null);
+ result.requestType(NameRequest.MAX_ENUM);
+ result.streamOutTo(this.peer());
+ }
+ /**
+ *
+ * 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 type be returned as well? This is only
+ * used to decide between LIST_VALUES and LIST_VALUE_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(this.peer());
+ }
+ }
+
+ // Send final null message
+ result.name(null);
+ result.type(null);
+ result.value(null);
+ result.requestType(NameRequest.MAX_ENUM);
+ result.streamOutTo(this.peer());
+ }
+
+ boolean done_ = false;
+
+
+ // References to the hash table and the timer queue
+ Hashtable mapping_;
+}
+
+
+/**
+ * A simple wrapper to keep the type and value together in
+ * the hash table.
+ */
+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/netsvcs/Naming/NameProxy.java b/java/netsvcs/Naming/NameProxy.java
new file mode 100644
index 00000000000..249f745f5ce
--- /dev/null
+++ b/java/netsvcs/Naming/NameProxy.java
@@ -0,0 +1,351 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameProxy.java
+ *
+ * This is a proxy which clients can use to interact with the naming service. They
+ * open a SOCKStream to the service, and can then call simple bind and resolve
+ * methods.
+ *
+ *@see netsvcs.Naming.NameAcceptor
+ *@see netsvcs.Naming.NameHandler
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Naming;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.SOCK_SAP.*;
+
+public class NameProxy
+{
+ /**
+ * Constructor
+ *
+ *@param socket A SOCKStream already connected to the naming service
+ */
+ public NameProxy(SOCKStream socket)
+ {
+ this.socket_ = socket;
+ }
+
+ /**
+ * 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.socket_);
+
+ // Create a reply
+ NameReply reply = new NameReply();
+
+ // Get the status of the bind from the naming service
+ reply.streamInFrom(this.socket_);
+
+ // 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.socket_);
+
+ // Get a response (hopefully with the value and type)
+ request.streamInFrom(this.socket_);
+
+ // 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.socket_);
+
+ NameReply reply = new NameReply();
+
+ // Get reply
+ reply.streamInFrom(this.socket_);
+
+ 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.socket_);
+
+ // Allocate and reuse the DIS here rather than each time we call
+ // streamInFrom
+ DataInputStream dis = new DataInputStream(this.socket_.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.socket_);
+
+ // Allocate the DIS here and reuse
+ DataInputStream dis = new DataInputStream(this.socket_.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;
+ }
+
+ // The SOCKStream used to communication with the service
+ SOCKStream socket_;
+};
+
+
+
+
+
+
+
diff --git a/java/netsvcs/Naming/NameReply.java b/java/netsvcs/Naming/NameReply.java
new file mode 100644
index 00000000000..52ebb111574
--- /dev/null
+++ b/java/netsvcs/Naming/NameReply.java
@@ -0,0 +1,145 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameReply.java
+ *
+ * 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 is
+ * unused (same in C++ version?).
+ *
+ *@see netsvcs.Naming.NameHandler
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Naming;
+
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.ASX.*;
+import JACE.SOCK_SAP.*;
+
+public class NameReply
+{
+ // Success and failure constants
+ public final static int SUCCESS = 1;
+ public final static int FAILURE = 2;
+
+ /**
+ * Default Constructor
+ */
+ 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
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bout);
+
+ dos.writeInt(this.length_);
+ dos.writeInt(this.type_);
+ dos.writeInt(this.errno_);
+
+ dos.flush();
+
+ byte[] array = bout.toByteArray();
+
+ sock.sendN(array, 0, array.length);
+ }
+
+ /**
+ * 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
+ {
+ DataInputStream dis = new DataInputStream(sock.inputStream());
+
+ this.streamInFrom(dis);
+ }
+
+ /**
+ * Send this data to the given 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();
+ }
+
+ final static int length_ = 12;
+
+ int type_;
+ int errno_;
+}
+
+
+
+
diff --git a/java/netsvcs/Naming/NameRequest.java b/java/netsvcs/Naming/NameRequest.java
new file mode 100644
index 00000000000..f8a3579fa35
--- /dev/null
+++ b/java/netsvcs/Naming/NameRequest.java
@@ -0,0 +1,331 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Naming
+ *
+ * = FILENAME
+ * NameRequest.java
+ *
+ * Used by both client and naming server as detailed in
+ * the NameHandler. This structure transfers information
+ * including name, value, type, and request type.
+ *
+ *@see netsvcs.Naming.NameHandler
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Naming;
+
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.ASX.*;
+import JACE.SOCK_SAP.*;
+
+public class NameRequest
+{
+ /**
+ * Different types of requests
+ */
+ public static final int BIND = 1;
+ public static final int REBIND = 2;
+ public static final int RESOLVE = 3;
+ public static final int UNBIND = 4;
+ public static final int LIST_NAMES = 5;
+ public static final int LIST_VALUES = 13;
+ public static final int LIST_TYPES = 21;
+ public static final int LIST_NAME_ENTRIES = 6;
+ public static final int LIST_VALUE_ENTRIES = 14;
+ public static final int LIST_TYPE_ENTRIES = 22;
+ public static final int MAX_ENUM = 11;
+
+ /**
+ * 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 socket
+ *
+ *@param sock Socket to read from
+ */
+ public void streamInFrom (JACE.SOCK_SAP.SOCKStream sock) throws IOException
+ {
+ DataInputStream dis = new DataInputStream(sock.inputStream());
+
+ this.streamInFrom(dis);
+ }
+
+ /**
+ * 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();
+
+ // 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);
+ }
+
+ /**
+ * Send this NameRequest out to the given SOCKStream
+ *
+ *@param sock SOCKStream to send to
+ */
+ public void streamOutTo (JACE.SOCK_SAP.SOCKStream sock) throws IOException
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bout);
+
+ 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();
+
+ byte[] array = bout.toByteArray();
+
+ sock.sendN(array, 0, array.length);
+ }
+
+ /**
+ * 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_;
+};
+
+
+
+
+
+