From ad242612b13512bef34dce62f6259b5df33d4067 Mon Sep 17 00:00:00 2001 From: eea1 Date: Tue, 24 Aug 1999 23:11:38 +0000 Subject: Updated source files for ServiceConfigurator. --- java/JACE/ServiceConfigurator/Service.java | 96 ++++ java/JACE/ServiceConfigurator/ServiceConfig.java | 482 +++++++++++++++++++++ java/JACE/ServiceConfigurator/ServiceLoader.java | 254 +++++++++++ java/JACE/ServiceConfigurator/ServiceObject.java | 130 ++++++ .../ServiceConfigurator/ServiceRepository.java | 274 ++++++++++++ java/JACE/ServiceConfigurator/package.html | 10 + 6 files changed, 1246 insertions(+) create mode 100644 java/JACE/ServiceConfigurator/Service.java create mode 100644 java/JACE/ServiceConfigurator/ServiceConfig.java create mode 100644 java/JACE/ServiceConfigurator/ServiceLoader.java create mode 100644 java/JACE/ServiceConfigurator/ServiceObject.java create mode 100644 java/JACE/ServiceConfigurator/ServiceRepository.java create mode 100644 java/JACE/ServiceConfigurator/package.html 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. + *

+ * 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. + *

+ * Implementing classes must also: + *

+ *

+ * Implementing classes should also: + *

+ * + *@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. + *

+ *@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. + *

+ *@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. + *

+ *@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. + *

+ *@return -1 on failure, 0 on success + */ + int fini (); + + /** + * Provide a status message for this service. + *

+ *@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. + *

+ *@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. + *

+ *@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.) + *

+ *@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. + *

+ * ServiceConfig files contain lines of the following forms: + * + *

+ *  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.]
+ * 
+ *

+ * Valid command line arguments: + *

+ *    -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)
+ * 
+ * + *@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 Specify name of the service config file"); + ACE.ERROR ("-d Enable debugging"); + ACE.ERROR ("-p If not found locally, search this URL path"); + ACE.ERROR (" for classes (multiple -p options allowed)"); + } + + /** Parse the command line. + *

+ * Currently, valid command line options are the following: + *

+   * -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)
+   * 
+ *@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. + *

+ * 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. + *

+ * 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 @@ + + + +Point for loading and managing services. +

+See also: + +Documents on the ACE Service Configurator + + -- cgit v1.2.1