summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-08-24 23:11:38 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1999-08-24 23:11:38 +0000
commit5ebd203fe7ad4fc0f807a0c23193db457c7f4f6a (patch)
treedf6da9d60ad9d444c88b68aa4e484bc764109fb2 /java
parent15a4b98d0e9cf4aa3a03f2610b1104bb7a7ec1c3 (diff)
downloadATCD-5ebd203fe7ad4fc0f807a0c23193db457c7f4f6a.tar.gz
Updated source files for ServiceConfigurator.
Diffstat (limited to 'java')
-rw-r--r--java/JACE/ServiceConfigurator/Service.java96
-rw-r--r--java/JACE/ServiceConfigurator/ServiceConfig.java482
-rw-r--r--java/JACE/ServiceConfigurator/ServiceLoader.java254
-rw-r--r--java/JACE/ServiceConfigurator/ServiceObject.java130
-rw-r--r--java/JACE/ServiceConfigurator/ServiceRepository.java274
-rw-r--r--java/JACE/ServiceConfigurator/package.html10
6 files changed, 1246 insertions, 0 deletions
diff --git a/java/JACE/ServiceConfigurator/Service.java b/java/JACE/ServiceConfigurator/Service.java
new file mode 100644
index 00000000000..fac0b0fc54b
--- /dev/null
+++ b/java/JACE/ServiceConfigurator/Service.java
@@ -0,0 +1,96 @@
+package JACE.ServiceConfigurator;
+
+/**
+ * Interface common to all services loaded with the
+ * Service Configurator.
+ * <P>
+ * In order to create a completely new type of service, all that
+ * is necessary is to implement this interface, and ServiceConfig
+ * will be able to load it. A concrete example is ServiceObject,
+ * the base class for the network services.
+ * <P>
+ * Implementing classes must also:
+ * <UL>
+ * <LI> Provide a default constructor
+ * <LI> Begin in their own thread (probably in init (String[]))
+ * </UL>
+ * <P>
+ * Implementing classes should also:
+ * <UL>
+ * <LI> Shut down completely when close () has been called. That
+ * means ending thread activity.
+ * </UL>
+ *
+ *@see JACE.ServiceConfigurator.ServiceObject
+ *@see JACE.ServiceConfigurator.ServiceConfig
+ *@author Everett Anderson
+ */
+public interface Service
+{
+ /**
+ * Temporarily disable this service. This will only be called for a
+ * service which returns false from its suspended() method.
+ * <P>
+ *@return -1 on failure, 0 on success
+ */
+ int suspend ();
+
+ /**
+ * Re-enable this service. This will only be called for a service
+ * which returns true from its suspended() method.
+ * <P>
+ *@return -1 on failure, 0 on success
+ */
+ int resume ();
+
+ /**
+ * Initialize this service. The arguments will be given as if they
+ * were from the command line, separated into Strings using spaces
+ * as the delimiters.
+ * <P>
+ *@param args set of command line arguments
+ *@return -1 on failure, 0 on success
+ */
+ int init (String [] args);
+
+ /**
+ * Close this service and free any internal resources.
+ * <P>
+ *@return -1 on failure, 0 on success
+ */
+ int fini ();
+
+ /**
+ * Provide a status message for this service.
+ * <P>
+ *@return status message
+ */
+ String info ();
+
+ /**
+ * Return the name of this service. The name is typically set
+ * in ServiceConfig to a name supplied in a configuration file.
+ * <P>
+ *@return name of this service
+ */
+ String name ();
+
+ /**
+ * Set the name of this service. This is typically caled in
+ * ServiceConfig, setting the name to one supplied in a configuration
+ * file.
+ * <P>
+ *@param name new name for this service
+ */
+ void name (String name);
+
+ /**
+ * Returns whether or not this service is suspended. The result
+ * determines whether or not this service's resume() and suspend()
+ * methods will be called by ServiceConfig. (For instance, while
+ * a service returns true, its suspend() method will not be called.)
+ * <P>
+ *@return true if suspended, else false
+ */
+ boolean suspended ();
+}
diff --git a/java/JACE/ServiceConfigurator/ServiceConfig.java b/java/JACE/ServiceConfigurator/ServiceConfig.java
new file mode 100644
index 00000000000..894cf415f06
--- /dev/null
+++ b/java/JACE/ServiceConfigurator/ServiceConfig.java
@@ -0,0 +1,482 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.ServiceConfigurator
+ *
+ * = FILENAME
+ * ServiceConfig.java
+ *
+ *************************************************/
+package JACE.ServiceConfigurator;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import JACE.OS.*;
+import JACE.Misc.*;
+
+/**
+ * Provide the base class that supplies common server daemon
+ * operations. Also provides a global point for interacting with
+ * the service repository. Services can be suspended, resumed,
+ * removed, and reloaded.
+ * <P>
+ * ServiceConfig files contain lines of the following forms:
+ *
+ * <PRE>
+ * load (Service Name) (Class Name) (Type) "argument list" (opt URL path)
+ *
+ * resume (Service Name)
+ * suspend (Service Name)
+ * remove (Service Name)
+ *
+ * where (Type) is currently only ServiceObject or Service_Object
+ * [Note: This is not enforced by the ServiceConfig program, but
+ * something must be there.]
+ * </PRE>
+ * <P>
+ * <B>Valid command line arguments:</B>
+ * <PRE>
+ * -f (filename) Specify name of the service config file
+ * -d Enable debugging
+ * -p (URL path) If not found locally, search this URL path
+ * for classes (multiple -p options allowed)
+ * </PRE>
+ *
+ *@author Prashant Jain
+ *@author Everett Anderson
+ */
+public class ServiceConfig
+{
+ /** Begins the process of loading a service configurator file:
+ * parses the command line and calls processDirectives
+ *
+ *@param args command line arguments to the Service Configurator
+ *@exception FileNotFoundException Couldn't find service config file
+ *@exception IOException Problem reading or parsing the config file
+ *@exception ClassNotFoundException Couldn't find a certain class
+ *@exception IllegalAccessException Inappropriate method call on a class
+ *@exception InstantiationException Couldn't create a certain class instance
+ *@return -1 on failure, 0 on success
+ */
+ public static int open (String [] args)
+ throws FileNotFoundException, IOException, ClassNotFoundException,
+ IllegalAccessException, InstantiationException
+ {
+ // Parse the command line
+ if (ServiceConfig.parseArgs (args) < 0) {
+ printUsage ();
+ return -1;
+ }
+
+ return ServiceConfig.processDirectives ();
+ }
+
+ protected static void printUsage ()
+ {
+ ACE.ERROR ("Valid options:\n");
+ ACE.ERROR ("-f <filename> Specify name of the service config file");
+ ACE.ERROR ("-d Enable debugging");
+ ACE.ERROR ("-p <URL path> If not found locally, search this URL path");
+ ACE.ERROR (" for classes (multiple -p options allowed)");
+ }
+
+ /** Parse the command line.
+ * <P>
+ * Currently, valid command line options are the following:
+ * <PRE>
+ * -d Debug mode
+ * -f (filename) Load services in the given file
+ * -p (URL path) If not found locally, search this URL path for classes
+ * (there can be multiple -p URL options)
+ * </PRE>
+ *@param args command line arguments
+ *@exception ClassNotFoundException Couldn't find a specified Service
+ *@exception IllegalAccessException Inappropriate method call on a Service
+ *@exception InstantiationException Couldn't create a Service instance
+ */
+ protected static int parseArgs (String [] args)
+ throws ClassNotFoundException, IllegalAccessException,
+ InstantiationException
+ {
+ GetOpt getopt = new GetOpt (args, "df:p:", true);
+ for (int c; (c = getopt.next ()) != -1; )
+ switch (c)
+ {
+ case 'p':
+ // Specify a URL path
+ try {
+ ServiceConfig.loader_.addURLPath (getopt.optarg ());
+ } catch (MalformedURLException e) {
+ ACE.ERROR ("Invalid URL: " + getopt.optarg ());
+ }
+ break;
+ /*
+ Not supported:
+
+ case 'b':
+ ServiceConfig.beADaemon_ = true;
+ break;
+ case 'n':
+ break;
+ */
+ case 'd':
+ ACE.enableDebugging ();
+ ACE.DEBUG ("Debugging is enabled");
+ break;
+ case 'f':
+ // Specify the file name of the config file
+ ServiceConfig.serviceConfigFile_ = getopt.optarg ();
+ break;
+ default:
+ ACE.ERROR ((char ) c + " is not a ServiceConfig option");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Uses the Service Repository to suspend a service with the given name.
+ *
+ *@param name name of the Service to suspend
+ *@return -1 on failure, 0 on success
+ */
+ public static int suspend (String name)
+ {
+ return ServiceConfig.svcRep_.suspend (name);
+ }
+
+ /**
+ * Uses the Service Repository to resume a service with the given name.
+ *
+ *@param name name of the Service to resume
+ *@return -1 on failure, 0 on success
+ */
+ public static int resume (String name)
+ {
+ return ServiceConfig.svcRep_.resume (name);
+ }
+
+ /**
+ * Removes the specified Service from the Service Repository.
+ *
+ *@param name name of the Service to remove
+ *@return -1 on failure, 0 on success
+ */
+ public static int remove (String name)
+ {
+ return ServiceConfig.svcRep_.remove (name);
+ }
+
+ /**
+ * Returns the info String from the specified Service.
+ *
+ *@param name name of the Service to query
+ *@return information about the Service
+ */
+ public static String info (String name)
+ {
+ return ServiceConfig.svcRep_.info (name);
+ }
+
+ /**
+ * Call fini on the specified Service.
+ *
+ *@param name name of the Service to shut down
+ *@return -1 on failure, 0 on success
+ */
+ public static int fini (String name)
+ {
+ return ServiceConfig.svcRep_.fini (name);
+ }
+
+ /**
+ * Call init on the specified Service. This is only needed
+ * when a user wants to add a Service to the repository without
+ * using service config files.
+ *
+ *@param name name of the Service to initialize
+ *@param args command line arguments to pass to the Service
+ *@return -1 on failure, 0 on success
+ *@see ServiceConfig#insert
+ */
+ public static int init (String name, String [] args)
+ {
+ return ServiceConfig.svcRep_.init (name, args);
+ }
+
+ /**
+ * Adds the given Service to the Service Repository. This is
+ * only needed when a user wants to add a Service to the repository
+ * without using service config files.
+ *
+ *@param service Service to insert
+ *@see ServiceConfig#init
+ */
+ public static void insert (Service service)
+ {
+ ServiceConfig.svcRep_.insert (service);
+ }
+
+ /**
+ * Check to see if the specified Service is suspended.
+ *
+ *@param name name of the Service to check
+ *@return true if it is suspended, else false
+ */
+ public static boolean suspended (String name)
+ {
+ return ServiceConfig.svcRep_.suspended (name);
+ }
+
+ /**
+ * Check to see if the repository contains a service with the given
+ * name.
+ *
+ *@param name name of the Service to check
+ *@return true if it is in the repository, else false
+ */
+ public static boolean contains (String name)
+ {
+ return (ServiceConfig.svcRep_.find (name) == null ? false : true);
+ }
+
+ /**
+ * Get an Enumeration of all of the names of the Services in the
+ * repository.
+ *
+ *@return Enumeration of Service names
+ */
+ public static Enumeration serviceNames ()
+ {
+ return ServiceConfig.svcRep_.serviceNames ();
+ }
+
+ /**
+ * Get an Enumeration of all Services in the repository.
+ *
+ *@return Enumeration of Services
+ */
+ public static Enumeration services ()
+ {
+ return ServiceConfig.svcRep_.services ();
+ }
+
+ /**
+ * Load a service of the given name, type, and arguments, then
+ * initialize it with the given arguments.
+ *
+ * Should be aware that this could also throw a class cast exception if
+ * the author of the service didn't implement the Service interface.
+ *
+ *@param serviceName name of the service to load
+ *@param className class name to load
+ *@param args command line arguments to initialize the service
+ *@exception ClassNotFoundException couldn't find the specified class file
+ *@exception IllegalAccessException problem calling a method on the service
+ *@exception InstantiationException problem creating an instance
+ *@exception IOException problem reading the class file
+ *@return -1 on failure, 0 on success
+ */
+ public static int load (String serviceName,
+ String className,
+ String [] args)
+ throws ClassNotFoundException, IllegalAccessException,
+ InstantiationException, IOException
+ {
+ Class svcClass = ServiceConfig.loader_.loadClass (className);
+
+ Service svc = (Service)(svcClass.newInstance());
+
+ svc.name (serviceName);
+
+ ServiceConfig.svcRep_.insert (svc);
+
+ return ServiceConfig.svcRep_.init (serviceName, args);
+ }
+
+ /**
+ * Same as load (String, String, String[]) but creates the
+ * String array from the given args parameter using the space
+ * character as a delimiter.
+ *
+ */
+ public static int load (String serviceName,
+ String className,
+ String args)
+ throws ClassNotFoundException, IllegalAccessException,
+ InstantiationException, IOException
+ {
+ return ServiceConfig.load (serviceName,
+ className,
+ OS.createStringArray (args, " "));
+ }
+
+ /**
+ * Parse a service configurator file, creating classes as necessary.
+ *
+ *@return -1 on failure, 0 on success
+ *@exception FileNotFoundException Couldn't find the file
+ *(default "svc.conf")
+ *@exception IOException Problem reading/parsing
+ *@exception ClassNotFoundException Couldn't find a certain class
+ *@exception IllegalAccessException Inappropriate method call
+ *@exception InstantiationException Couldn't create a class instance
+ */
+ protected static int processDirectives ()
+ throws FileNotFoundException, IOException, ClassNotFoundException,
+ IllegalAccessException, InstantiationException
+ {
+ ACE.DEBUG("Processing directives in file " +
+ ServiceConfig.serviceConfigFile_);
+
+ File configFile = new File (ServiceConfig.serviceConfigFile_);
+
+ // Check if file exists and is a normal file
+ if (!configFile.exists () || !configFile.isFile ())
+ throw new FileNotFoundException ("File " +
+ ServiceConfig.serviceConfigFile_ +
+ " not found");
+
+ // Check if the file is readable
+ if (!configFile.canRead ())
+ throw new IOException ("File " +
+ ServiceConfig.serviceConfigFile_ +
+ " not readable");
+
+ // Set up the stream
+ FileInputStream fileIn = new FileInputStream (configFile);
+
+ // Parse the file
+ Reader r = new BufferedReader(new InputStreamReader(fileIn));
+ StreamTokenizer in = new StreamTokenizer (r);
+
+ // Set characters in ASCII range 32 to 47, ASCII range 91 to 96,
+ // and ASCII range 123 to 126 as ordinary characters
+ in.wordChars ('.', '/'); // ASCII range 32 to 47
+ in.wordChars (':', '@'); // ASCII range 58 to 64
+ in.wordChars ('[', '`'); // ASCII range 91 to 96
+ in.wordChars ('{', '~'); // ASCII range 123 to 126
+ in.quoteChar ('\"');
+ in.commentChar ('#');
+ in.eolIsSignificant(true);
+ in.lowerCaseMode(false);
+
+ Vector strs = new Vector();
+ int lineNumber = 1;
+
+ while (in.nextToken () != StreamTokenizer.TT_EOF) {
+
+ if (in.ttype == StreamTokenizer.TT_EOL) {
+
+ String command = ((String)strs.elementAt(COMMAND_NAME)).toLowerCase();
+ String name = (String)strs.elementAt(SERVICE_NAME);
+
+ if (strs.size() == 2) {
+ if (command.equals("remove"))
+ ServiceConfig.remove(name);
+ else
+ if (command.equals("suspend"))
+ ServiceConfig.suspend(name);
+ else
+ if (command.equals("resume"))
+ ServiceConfig.resume(name);
+ } else {
+
+ if (!command.equals("load"))
+ throw new IOException ("Unknown command: " +
+ command +
+ " at line " +
+ lineNumber);
+
+ if (strs.size() < 5)
+ throw new IOException ("Line " + lineNumber +
+ " requires 5 values, not " +
+ strs.size());
+
+ // Type is currently unenforced since everything must descend
+ // from Service anyway.
+ //String type = (String)strs.elementAt (SERVICE_TYPE);
+ String className = (String)strs.elementAt (CLASS_NAME);
+
+ if (strs.size () > CODE_BASE) {
+ try {
+ String url = (String)strs.elementAt (CODE_BASE);
+
+ ServiceConfig.loader_.addURLPath (url);
+
+ } catch (MalformedURLException e) {
+ ACE.ERROR("Bad code base on line " + lineNumber);
+ }
+ }
+
+ ServiceConfig.load(name,
+ className,
+ (String)strs.elementAt(ARGS));
+ }
+
+ lineNumber++;
+ strs.removeAllElements();
+ continue;
+ }
+
+ // Skip over non-strings
+ if ((in.ttype == StreamTokenizer.TT_WORD) ||
+ (in.ttype == '\"'))
+ strs.addElement(new String(in.sval));
+ else
+ ACE.DEBUG ("Invalid string on line " + lineNumber +
+ " element " + strs.size() +
+ " type " + in.ttype);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Close all services.
+ */
+ public static void close ()
+ {
+ ServiceConfig.svcRep_.close ();
+ }
+
+ /**
+ * Return a reference to the ServiceLoader used to load
+ * classes.
+ *
+ *@return ServiceLoader used internally by ServiceConfig.
+ */
+ public static ServiceLoader loader ()
+ {
+ return ServiceConfig.loader_;
+ }
+
+ /**
+ * Specify the ServiceLoader to be used by ServiceConfig.
+ *
+ *@param loader ServiceLoader instance to use (should support remote
+ * loading)
+ */
+ public static void loader (ServiceLoader loader)
+ {
+ ServiceConfig.loader_ = loader;
+ }
+
+ // Set by command line options
+ private static boolean beADaemon_ = false;
+
+ private static String serviceConfigFile_ = "svc.conf";
+
+ private static ServiceRepository svcRep_ = new ServiceRepository ();
+ private static ServiceLoader loader_ = new ServiceLoader ();
+
+ // Order for the commands on a line in the config file
+ private final static int COMMAND_NAME = 0;
+ private final static int SERVICE_NAME = 1;
+ private final static int CLASS_NAME = 2;
+ private final static int SERVICE_TYPE = 3;
+ private final static int ARGS = 4;
+ private final static int CODE_BASE = 5;
+}
diff --git a/java/JACE/ServiceConfigurator/ServiceLoader.java b/java/JACE/ServiceConfigurator/ServiceLoader.java
new file mode 100644
index 00000000000..75297f9631d
--- /dev/null
+++ b/java/JACE/ServiceConfigurator/ServiceLoader.java
@@ -0,0 +1,254 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.ServiceConfigurator
+ *
+ * = FILENAME
+ * ServiceLoader.java
+ *
+ * Implementation of a network-capable class loader
+ *
+ *@author Prashant Jain
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.ServiceConfigurator;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import JACE.OS.*;
+import JACE.Misc.*;
+
+/**
+ * ClassLoader that can load classes from across the network
+ * via provided URL search paths, or from the local machine.
+ * <P>
+ * This operates in the same way as the JDK 1.2 ClassLoader by
+ * first checking for preloaded classes, then trying to use the system
+ * loader, and finally trying to load it via the network. The user can also
+ * provide URL search paths, or explicitly call the loadClass method which
+ * takes a URL.
+ *
+ *@see java.lang.ClassLoader
+ *@see java.lang.Class
+ */
+public class ServiceLoader extends ClassLoader
+{
+ /**
+ * Creates a loader that will only search the local machine for classes
+ * until URL paths are registered via addURLPath.
+ */
+ public ServiceLoader ()
+ {
+ this.URLSearchPaths_ = new Vector();
+ }
+
+ /**
+ * Creates a loader that will search the local machine followed by
+ * this array of URL paths when loading classes. Note that additional
+ * paths can be added later with the addURLPath method.
+ *@param remotePaths array of URLs to search when loading classes, after
+ *attempts to load from the local machine have failed
+ */
+ public ServiceLoader (URL remotePaths[])
+ {
+ this();
+
+ if (remotePaths == null)
+ return;
+
+ for (int i = 0; i < remotePaths.length; i++)
+ this.addURLPath(remotePaths[i]);
+ }
+
+ /**
+ * Add the given URL to the list of URL paths to search when loading
+ * classes.
+ *@param url URL ending in '/' where classes can be found
+ */
+ public void addURLPath (URL url)
+ {
+ if (!URLSearchPaths_.contains(url))
+ URLSearchPaths_.addElement(url);
+ }
+
+ /**
+ * Add the given URL to the list of URL paths to search when loading
+ * classes.
+ *@param String representation of a URL ending in '/'
+ *@exception MalformedURLException the given String wasn't a valid URL
+ */
+ public void addURLPath (String url) throws MalformedURLException
+ {
+ URL resource = new URL (url);
+ this.addURLPath (resource);
+ }
+
+ /**
+ * Tries to load the given class by following the example of JDK 1.2
+ * ClassLoader. First check loaded classes, then try to use the system
+ * loader, and only then perform the user defined subclass behavior
+ * from findClass (in this case, it's searching over the network).
+ *@param name name of the class to load
+ *@param resolve whether or not to resolve the class
+ *@exception ClassNotFoundException if the class could not be found
+ *@return loaded Class instance
+ */
+ protected Class loadClass(String name,
+ boolean resolve)
+ throws ClassNotFoundException
+ {
+
+ Class c = null;
+
+ // Has this class already been loaded once?
+ c = findLoadedClass(name);
+ if (c != null)
+ return c;
+
+ try {
+
+ // Can the system loader find it?
+ c = findSystemClass(name);
+ return c;
+
+ } catch (ClassNotFoundException e2) {
+ // The system loader couldn't find it
+ }
+
+ // If none of the above, try searching our way
+ return findClass(name);
+ }
+
+ /**
+ * This should duplicate the behavior of this class in JDK 1.2. It is
+ * called by the protected loadClass method after trying to load the
+ * class in other ways. It simply calls loadClassData and then defines
+ * the class.
+ *@param name name of the class to load
+ *@exception ClassNotFoundException couldn't find the class
+ *@return loaded Class
+ */
+ protected Class findClass(String name) throws ClassNotFoundException
+ {
+ byte[] b = loadClassData(name);
+ return defineClass(name, b, 0, b.length);
+ }
+
+ /**
+ * Try loading a class with the given name, searching the remote
+ * URL paths that have been registered. Note that this will only
+ * be called after first checking to see if the class has already
+ * been loaded, then checking to see whether or not the system
+ * loader can find it.
+ * <P>
+ * This could be overriden by subclasses to define different
+ * loading behavior.
+ *
+ *@param className name of the class (not file name) of the class to load
+ *@exception ClassNotFoundException couldn't find the class
+ *@return bytes of a .class file
+ */
+ private byte[] loadClassData(String className) throws ClassNotFoundException
+ {
+ byte data[] = null;
+
+ // Try to load it by reading in the bytes from the net
+ Enumeration e = URLSearchPaths_.elements();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ URL path = (URL)e.nextElement();
+ URL classFileURL;
+
+ try
+ {
+ classFileURL = new URL(path.toExternalForm() +
+ className +
+ ".class");
+ } catch (MalformedURLException ex) {
+ ACE.ERROR("Bad URL: " + ex.getMessage());
+ continue;
+ }
+
+ ACE.DEBUG("Looking for " + classFileURL.toExternalForm());
+ URLConnection urlConnection = classFileURL.openConnection ();
+
+ // Get the input stream associated with the URL connection and
+ // pipe it to a newly created DataInputStream
+ DataInputStream i = new DataInputStream
+ (urlConnection.getInputStream ());
+
+ // Allocate a buffer big enough to hold the contents of the
+ // data we are about to read
+ data = new byte [urlConnection.getContentLength ()];
+
+ // Now read all the data into the buffer
+ i.readFully (data);
+
+ } catch (IOException ex) {
+ // Either the URL wasn't there or we couldn't get the data
+ continue;
+ }
+ }
+
+ // Couldn't find it or it loaded improperly
+ if (data == null)
+ throw new ClassNotFoundException("Can't obtain " + className);
+
+ return data;
+ }
+
+ /**
+ * Load a class from across the network
+ *
+ * The newer way to do this is similar to JDK 1.2 URLClassLoader:
+ * Add URLs that end in '/' via the addURLPath method
+ * Call loadClass (class name without .class extension) method
+ *
+ *@param url URL of the class to load
+ *@exception ClassNotFoundException Couldn't find the class
+ *@return loaded Class
+ */
+ public Class loadClass (URL url) throws ClassNotFoundException
+ {
+ // Extract the name of the class from the URL
+ String URLPath = url.getFile();
+
+ // Get the class name by removing any directory information
+ int idx = URLPath.lastIndexOf("/");
+ if (idx == -1)
+ throw new ClassNotFoundException("Can't find " + URLPath);
+ String className = URLPath.substring(idx + 1);
+ URLPath = URLPath.substring(0, idx + 1);
+
+ // Get rid of the class suffix
+ idx = className.lastIndexOf(".class");
+ if (idx != -1)
+ className = className.substring(0, idx);
+
+ ACE.DEBUG("The name of the class about to load is " + className);
+
+ try {
+ // Add the URL to the list of URL search paths
+ URL path = new URL(URLPath);
+
+ this.addURLPath(path);
+
+ } catch (MalformedURLException e) {
+ throw new ClassNotFoundException("Can't find " + URLPath);
+ }
+
+ // Try to load the class
+ return loadClass(className);
+ }
+
+ /**
+ * Collection of URLs which end in the HTTP path separator. Used
+ * for searching for classes across the network.
+ */
+ protected Vector URLSearchPaths_;
+}
diff --git a/java/JACE/ServiceConfigurator/ServiceObject.java b/java/JACE/ServiceConfigurator/ServiceObject.java
new file mode 100644
index 00000000000..4538698e8a6
--- /dev/null
+++ b/java/JACE/ServiceConfigurator/ServiceObject.java
@@ -0,0 +1,130 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.ServiceConfigurator
+ *
+ * = FILENAME
+ * ServiceObject.java
+ *
+ *@author Prashant Jain
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.ServiceConfigurator;
+
+import java.io.*;
+import JACE.ASX.*;
+import JACE.Reactor.*;
+
+/**
+ * Provides a default implementation of the Service interface, and can also
+ * be registered with the Reactor.
+ *
+ *@see JACE.Reactor
+ *@see Service
+ */
+public class ServiceObject implements EventHandler, Service
+{
+ /**
+ * Initialize object when dynamic loading occurs. Overwrite this
+ * method to do anything useful.
+ *@return -1 (default implementation)
+ */
+ public int init (String [] args)
+ {
+ return -1;
+ }
+
+ /**
+ * Terminate the object. Note that an object can not be explicitly
+ * unloaded. Overwrite this method to do anything useful.
+ *@return -1 (default implementation)
+ */
+ public int fini ()
+ {
+ return -1;
+ }
+
+ /**
+ * Get information on an active object. Overwrite this method to do
+ * anything useful.
+ *@return null (default implementation)
+ */
+ public String info ()
+ {
+ return null;
+ }
+
+ /**
+ * Called when timer expires. Overwrite this method to do
+ * anything useful.
+ *@param tv Time Value for when timer expired
+ *@param obj An arbitrary object that was passed to the Timer Queue
+ * (Asynchronous Completion Token)
+ *@return -1
+ */
+ public int handleTimeout (TimeValue tv, Object obj)
+ {
+ return -1;
+ }
+
+ /**
+ * Request that this service suspend activity. Overwrite this
+ * method to do anything useful. Currently, this sets an internal
+ * state variable to true.
+ */
+ public int suspend ()
+ {
+ this.suspended_ = true;
+
+ return 0;
+ }
+
+ /**
+ * Request that this service resume activity. Currently, this sets
+ * an internal state variable to false.
+ */
+ public int resume ()
+ {
+ this.suspended_ = false;
+
+ return 0;
+ }
+
+ /**
+ * Is this service suspended?
+ */
+ public boolean suspended ()
+ {
+ return this.suspended_;
+ }
+
+ /**
+ * Return the name of the Service. Implementation provided.
+ */
+ public String name ()
+ {
+ return this.name_;
+ }
+
+ /**
+ * Set the name of the Service. Should be called when a Service is
+ * created -- this is done automatically by ServiceConfig when loading
+ * from a file. Implementation provided.
+ */
+ public void name (String name)
+ {
+ this.name_ = name;
+ }
+
+ /**
+ * Name of this ServiceObject.
+ */
+ protected String name_ = null;
+
+ /**
+ * Status of whether this ServiceObject is suspended or not.
+ * (Initially false)
+ */
+ protected boolean suspended_ = false;
+}
diff --git a/java/JACE/ServiceConfigurator/ServiceRepository.java b/java/JACE/ServiceConfigurator/ServiceRepository.java
new file mode 100644
index 00000000000..33f9a088077
--- /dev/null
+++ b/java/JACE/ServiceConfigurator/ServiceRepository.java
@@ -0,0 +1,274 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * JACE.ServiceConfigurator
+ *
+ * = FILENAME
+ * ServiceRepository.java
+ *
+ * The service repository stores the network services, allowing them to be
+ * removed, suspended, resumed, etc.
+ *
+ *@see JACE.ServiceConfigurator.ServiceConfig;
+ *@see JACE.ServiceConfigurator.Service;
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package JACE.ServiceConfigurator;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Stores Services, providing operations such as remove, suspend, resume, etc.
+ */
+public class ServiceRepository
+{
+ /**
+ * Constructor
+ */
+ public ServiceRepository ()
+ {
+ this.serviceMap_ = new Hashtable ();
+ this.serviceNames_ = new Vector ();
+ }
+
+ /**
+ * Constructor
+ *
+ *@param initialSize Initial vector size for the repository
+ */
+ public ServiceRepository (int initialSize)
+ {
+ this.serviceMap_ = new Hashtable (initialSize);
+ this.serviceNames_ = new Vector (initialSize);
+ }
+
+ /**
+ * Shut down all the services, closing them in reverse order of insertion.
+ * This calls fini on each service.
+ *@return -1 on failure, 0 on sucess
+ */
+ public int close()
+ {
+ int result = 0;
+
+ for (int i = this.size() - 1; i >= 0; i--) {
+
+ String name = (String)this.serviceNames_.elementAt (i);
+
+ Service s = (Service)this.serviceMap_.get (name);
+
+ result = (s.fini () == -1 ? -1 : result);
+ }
+
+ this.serviceMap_.clear ();
+ this.serviceNames_.removeAllElements ();
+
+ return result;
+ }
+
+ /**
+ * Insert a Service into the repository.
+ * (If already in, calls fini() and replaces)
+ *
+ *@param service Service to add
+ */
+ public void insert (Service service)
+ {
+ String name = service.name ();
+ Service alreadyIn = this.find (name);
+
+ if (alreadyIn != null) {
+
+ alreadyIn.fini ();
+ this.remove (alreadyIn);
+
+ } else {
+
+ this.serviceMap_.put (name, service);
+ this.serviceNames_.addElement (name);
+
+ }
+ }
+
+ /**
+ * Returns an enumeration of all the Service objects.
+ *
+ */
+ public Enumeration services ()
+ {
+ return this.serviceMap_.elements ();
+ }
+
+ /**
+ * Returns an enumeration of all the Service names
+ */
+ public Enumeration serviceNames ()
+ {
+ return this.serviceMap_.keys ();
+ }
+
+ /**
+ * Convenience method that returns null when the service isn't
+ * found.
+ */
+ public Service find (String name)
+ {
+ Object serviceObj = this.serviceMap_.get (name);
+
+ if (serviceObj == null)
+ return null;
+
+ return (Service)serviceObj;
+ }
+
+ /**
+ * Finds the Service associated with a given
+ * name.
+ *
+ *@param name Name of the service to find
+ *@exception NoSuchElementException if the given service is not found
+ */
+ protected Service findService (String name) throws NoSuchElementException
+ {
+ Object serviceObj = this.serviceMap_.get (name);
+
+ if (serviceObj == null)
+ throw new NoSuchElementException ("Service " + name + " not found.");
+
+ return (Service)serviceObj;
+ }
+
+ /**
+ * Removes the given Service and calls its fini () method.
+ *@param service Service to remove
+ *@return -1 on failure, 0 on success
+ */
+ protected int remove (Service service)
+ {
+ String name = service.name ();
+
+ this.serviceMap_.remove (name);
+
+ int index = this.serviceNames_.indexOf (name);
+
+ this.serviceNames_.removeElementAt (index);
+
+ return service.fini ();
+ }
+
+ /**
+ * Shut down the specified Service.
+ *
+ *@param name name of the Service to shut down
+ *@return -1 on failure, 0 on success
+ */
+ public int fini (String name)
+ {
+ Service service = this.findService (name);
+
+ return service.fini ();
+ }
+
+ /**
+ * Remove the specified Service, calling its fini () method.
+ *
+ *@param name name of the Service to remove
+ *@return -1 on failure, 0 on success
+ */
+ public int remove (String name)
+ {
+ Service service = this.findService (name);
+
+ return this.remove (service);
+ }
+
+ /**
+ * Resume a suspended service
+ *@param name Name of the service to resume
+ *@return -1 on failure, 0 on success
+ */
+ public int resume (String name)
+ {
+ Service service = this.findService (name);
+
+ return service.resume();
+ }
+
+ /**
+ * Suspend a service
+ *@param name Name of the service to suspend
+ *@return -1 on failure, 0 on success
+ */
+ public int suspend (String name)
+ {
+ Service service = this.findService (name);
+
+ if (service.suspended ())
+ return 0;
+
+ return service.suspend ();
+ }
+
+ /**
+ * Returns status information about the specified Service.
+ *
+ *@param name name of the Service to query
+ *@return String of information about the Service's status
+ */
+ public String info (String name)
+ {
+ Service service = this.findService (name);
+
+ return service.info ();
+ }
+
+ /**
+ * Check to see if the specified Service is suspended or not
+ */
+ public boolean suspended (String name)
+ {
+ Service service = this.findService (name);
+
+ return service.suspended ();
+ }
+
+ /**
+ * Initialize the specified Service with the given command
+ * line arguments.
+ */
+ public int init (String name, String [] args)
+ {
+ Service service = this.findService (name);
+
+ return service.init (args);
+ }
+
+ /**
+ * Returns the number of items in the repository
+ */
+ public int size ()
+ {
+ return this.serviceNames_.size();
+ }
+
+ /**
+ * Stores the Service names in order of insertion
+ */
+ Vector serviceNames_;
+
+ /**
+ * A mapping between Service names and Service objects
+ */
+ Hashtable serviceMap_;
+};
+
+
+
+
+
+
+
+
diff --git a/java/JACE/ServiceConfigurator/package.html b/java/JACE/ServiceConfigurator/package.html
new file mode 100644
index 00000000000..2092fc34f5a
--- /dev/null
+++ b/java/JACE/ServiceConfigurator/package.html
@@ -0,0 +1,10 @@
+<!-- $Id$ -->
+<HTML>
+<BODY>
+Point for loading and managing services.
+<P>
+See also:
+<a href="http://www.cs.wustl.edu/~schmidt/ACE-papers.html#config">
+Documents on the ACE Service Configurator</a>
+</BODY>
+</HTML>