User: mulder
Date: 00/09/13 04:39:57
Modified: src/main/org/jboss/dependencies DependencyManager.java
Log:
Add standard jBoss comments, and JavaDoc comments.
Try to start MBeans that are not services.
Change a couple method names for clarity.
Revision Changes Path
1.2 +142 -52 jboss/src/main/org/jboss/dependencies/DependencyManager.java
Index: DependencyManager.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/dependencies/DependencyManager.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DependencyManager.java 2000/09/13 02:06:01 1.1
+++ DependencyManager.java 2000/09/13 11:39:57 1.2
@@ -1,3 +1,9 @@
+/*
+ * jBoss, the OpenSource EJB server
+ *
+ * Distributable under GPL license.
+ * See terms of license at gnu.org.
+ */
package org.jboss.dependencies;
import java.io.IOException;
@@ -15,23 +21,50 @@
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.sun.xml.parser.Parser;
-import com.sun.xml.parser.Resolver;
+/**
+ * Manages dependencies between MBeans. Loads an XML configuration file,
+ * and then starts a list of MBeans according to the dependencies in the
+ * file.
+ * @author Aaron Mulder <[EMAIL PROTECTED]>
+ * @version $Revision: 1.2 $
+ */
public class DependencyManager {
+ // Static --------------------------------------------------------
+
+ /**
+ * Set this to true to enable verbose console output (as each MBean
+ * is loaded)
+ */
private final static boolean DEBUG=false;
+
+ // Attributes ----------------------------------------------------
+
private HashMap dependencies;
private HashSet loadedBeans;
private HashMap remainingBeans;
private HashSet pendingBeans;
+ private HashSet otherMBeans;
private MBeanServer server;
+ // Constructors --------------------------------------------------
+
+ /**
+ * Initializes a DependencyManager.
+ */
public DependencyManager() {
dependencies = new HashMap();
loadedBeans = new HashSet();
remainingBeans = new HashMap();
pendingBeans = new HashSet();
+ otherMBeans = new HashSet();
}
+ // Public --------------------------------------------------------
+
+ /**
+ * Loads dependency configuration from an XML string.
+ */
public void loadXML(String source) {
dependencies.clear();
Parser parser = new Parser();
@@ -46,36 +79,80 @@
}
}
+ /**
+ * Starts all the MBeans in a server in an order consistant with the
+ * dependencies.
+ */
public void startMBeans(MBeanServer server) {
this.server = server;
loadedBeans.clear();
remainingBeans.clear();
pendingBeans.clear();
+ otherMBeans.clear();
Iterator it = server.queryNames(null, null).iterator();
+
+ // Identify all the MBeans
while(it.hasNext()) {
ObjectName name = (ObjectName)it.next();
String service = getService(name);
- if(service == null)
+ if(service == null) {
+ otherMBeans.add(name);
continue;
+ }
Set set = (Set)remainingBeans.get(service);
if(set == null)
set = new HashSet();
set.add(name);
remainingBeans.put(service, set);
}
+
+ // Start all the MBeans that are services
it = ((Map)remainingBeans.clone()).keySet().iterator();
while(it.hasNext()) {
String next = (String)it.next();
- if(!processMBean(next)) {
- System.out.println("Unable to load service '"+next+"'");
+ if(!processService(next)) {
+ System.out.println("Unable to start service '"+next+"'");
+ }
+ }
+
+ // Start all the MBeans that are not services
+ it = otherMBeans.iterator();
+ while(it.hasNext()) {
+ ObjectName name = (ObjectName)it.next();
+ if(!startMBean(name)) {
+ System.out.println("Unable to start MBean
'"+name.getCanonicalName()+"'");
}
}
- System.out.println(loadedBeans.size()+" services loaded.");
+
+ // Clear out remaining data structures.
+ System.out.println(loadedBeans.size()+" services and "+otherMBeans.size()+"
other MBeans started.");
loadedBeans.clear();
dependencies.clear();
+ otherMBeans.clear();
+ }
+
+ /**
+ * Prints all the dependencies to the console.
+ */
+ public void printDependencies() {
+ Iterator it = dependencies.keySet().iterator();
+ while(it.hasNext()) {
+ String key = (String)it.next();
+ Iterator child = ((HashSet)dependencies.get(key)).iterator();
+ while(child.hasNext()) {
+ Dependency dep = (Dependency)child.next();
+ System.out.println(key+" depends on "+dep.name+(dep.required ? "
REQUIRED" : ""));
+ }
+ }
}
- private boolean processMBean(String target) {
+ // Private -------------------------------------------------------
+
+ /**
+ * Loads all the dependencies for a service, and then the service itself.
+ * This is a recursive process.
+ */
+ private boolean processService(String target) {
if(pendingBeans.contains(target))
throw new RuntimeException("Circular dependencies!");
if(loadedBeans.contains(target))
@@ -84,47 +161,36 @@
pendingBeans.add(target);
Set set = (Set)dependencies.get(target);
if(set == null) {
- return loadMBean(target);
+ return loadService(target);
} else {
Iterator it = set.iterator();
while(it.hasNext()) {
Dependency dep = (Dependency)it.next();
if(DEBUG) System.out.println(" Service '"+target+"' depends on
'"+dep.name+"'");
if(!loadedBeans.contains(dep.name)) {
- boolean result = processMBean(dep.name);
+ boolean result = processService(dep.name);
if(!result && dep.required)
return false;
}
}
- return loadMBean(target);
+ return loadService(target);
}
}
- private boolean loadMBean(String target) {
+ /**
+ * Loads all instances of a service. That is, all MBeans which have
+ * "service=target" in the ObjectName.
+ */
+ private boolean loadService(String target) {
boolean loaded = false;
Set set = (Set)remainingBeans.get(target);
if(set != null) {
if(DEBUG) System.out.println("Starting service '"+target+"'");
Iterator it = set.iterator();
while(it.hasNext()) {
- ObjectName name = (ObjectName)it.next();
- if(DEBUG) System.out.println("Starting instance
'"+name.getCanonicalName()+"'");
- try {
- server.invoke(name, "start", new Object[0], new String[0]);
- loaded = true;
- } catch(ReflectionException e) {
- if(e.getTargetException() instanceof NoSuchMethodException) {
- loaded = true; // This bean doesn't have a start!
- } else {
- System.out.println("Error starting service
'"+name.getCanonicalName()+"': "+e.getTargetException());
- loaded = false;
- break;
- }
- } catch(Throwable t) {
- System.out.println("Error starting service
'"+name.getCanonicalName()+"': "+t);
- loaded = false;
+ loaded = startMBean((ObjectName)it.next());
+ if(!loaded)
break;
- }
}
remainingBeans.remove(target);
dependencies.remove(target);
@@ -134,6 +200,32 @@
return loaded;
}
+ /**
+ * Calls the "start" method on an MBean. If no such method is available,
+ * that's OK, but if the call fails for another reason, returns false.
+ */
+ private boolean startMBean(ObjectName name) {
+ boolean loaded = false;
+ if(DEBUG) System.out.println("Starting instance
'"+name.getCanonicalName()+"'");
+ try {
+ server.invoke(name, "start", new Object[0], new String[0]);
+ loaded = true;
+ } catch(ReflectionException e) {
+ if(e.getTargetException() instanceof NoSuchMethodException) {
+ loaded = true; // This bean doesn't have a start!
+ } else {
+ System.out.println("Error starting service
'"+name.getCanonicalName()+"': "+e.getTargetException());
+ }
+ } catch(Throwable t) {
+ System.out.println("Error starting service
'"+name.getCanonicalName()+"': "+t);
+ }
+ return loaded;
+ }
+
+ /**
+ * Finds the substring "service=XXX" in an ObjectName.
+ * @return The XXX part, or null if there is no such substring.
+ */
private String getService(ObjectName oName) {
String name = oName.getCanonicalName();
int pos = name.indexOf("service=");
@@ -148,38 +240,23 @@
end = test;
return name.substring(pos+8, end);
}
-
- public void dump() {
- Iterator it = dependencies.keySet().iterator();
- while(it.hasNext()) {
- String key = (String)it.next();
- Iterator child = ((HashSet)dependencies.get(key)).iterator();
- while(child.hasNext()) {
- Dependency dep = (Dependency)child.next();
- System.out.println(key+" depends on "+dep.name+(dep.required ? "
REQUIRED" : ""));
- }
- }
- }
-
- public static void main(String args[]) {
- StringBuffer total = new StringBuffer();
- try{
- java.io.BufferedReader reader = new java.io.BufferedReader(new
java.io.FileReader(new java.io.File(args[0])));
- String line;
- while((line = reader.readLine()) != null)
- total.append(line).append('\n');
- DependencyManager dm = new DependencyManager();
- dm.loadXML(total.toString());
- dm.dump();
- } catch(IOException e) {e.printStackTrace();}
- }
+ // Inner classes -------------------------------------------------
private class SAXHandler extends HandlerBase {
private String currentService;
+
+ /**
+ * Clears the current service.
+ */
public void endElement(String name) throws SAXException {
if(name.equals("service"))
currentService = null;
}
+
+ /**
+ * Records the current service, or a dependency for the current
+ * service.
+ */
public void startElement(String name, AttributeList atts) throws
SAXException {
if(name.equals("service")) {
currentService = atts.getValue("name");
@@ -192,10 +269,23 @@
}
}
+/**
+ * A record of a dependency.
+ */
class Dependency {
+ /**
+ * The name of the service that should be loaded first.
+ */
public String name;
+ /**
+ * <B>True</B> if the service <I>must</I> be loaded first, <B>false</B> if
+ * the service should be loaded first only if available.
+ */
public boolean required;
+ /**
+ * Creates a new dependency record.
+ */
public Dependency(String name, String required) {
this.name = name;
this.required = new Boolean(required).booleanValue();