User: d_jencks Date: 01/11/10 13:38:07 Modified: src/main/org/jboss/system ServiceConfigurator.java ServiceController.java ServiceControllerMBean.java URLClassLoader.java Log: Changed mbean dependencies to work directly by mbean-references: eliminated depends tag from *service.xml files Revision Changes Path 1.5 +114 -20 jboss/src/main/org/jboss/system/ServiceConfigurator.java Index: ServiceConfigurator.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/system/ServiceConfigurator.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- ServiceConfigurator.java 2001/09/11 18:35:03 1.4 +++ ServiceConfigurator.java 2001/11/10 21:38:06 1.5 @@ -6,41 +6,43 @@ */ package org.jboss.system; -import java.io.Writer; -import java.io.StringWriter; -import java.util.Hashtable; + + + + import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; +import java.io.StringWriter; +import java.io.Writer; import java.lang.reflect.Method; import java.lang.reflect.Method; import java.lang.reflect.Modifier; - -import javax.management.MBeanInfo; +import java.util.ArrayList; +import java.util.Hashtable; import javax.management.Attribute; -import javax.management.ObjectName; -import javax.management.MBeanServer; -import javax.management.ObjectInstance; -import javax.management.MBeanAttributeInfo; import javax.management.InstanceNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; - +import javax.management.ObjectInstance; +import javax.management.ObjectName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Text; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Document; - +import org.jboss.deployment.DeploymentException; import org.jboss.logging.Logger; import org.jboss.util.DOMWriter; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; /** * Service configuration helper. * * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Hiram Chirino</a> - * @version $Revision: 1.4 $ + * @version $Revision: 1.5 $ * * <p><b>20010830 marc fleury:</b> * <ul> @@ -149,7 +151,20 @@ // Public ----------------------------------------------------- - public void configure(Element mbeanElement) + /** + * The <code>configure</code> method configures an mbean based on the xml element configuration + * passed in. Three formats are supported: + * <attribute name="(name)">(value)</attribute> + * <mbean-ref name="(name)">(object name of mbean referenced)</mbean-ref> + * <mbean-ref-list name="(name)"> + * [list of] </mbean-ref-list-element>(object name)</mbean-ref-list-element> + * </mbean-ref-list> + * + * @param mbeanElement an <code>Element</code> value + * @return a <code>ArrayList</code> of all the mbeans this one references. + * @exception Exception if an error occurs + */ + public ArrayList configure(Element mbeanElement) throws Exception { @@ -163,8 +178,10 @@ info = server.getMBeanInfo(objectName); } catch (InstanceNotFoundException e) { // The MBean is no longer available - // It's ok, just return - return; + // It's ok, just return It is ????? Why?? Oh yeah? + throw new DeploymentException("trying to configure nonexistent mbean: " + objectName); + //log.debug("object name " + objectName + " is no longer available"); + //return true; } // Set attributes @@ -218,6 +235,83 @@ } } } + // Set mbean references (object names) + ArrayList mBeanRefs = new ArrayList(); + NodeList mbeanRefElements = mbeanElement.getElementsByTagName("mbean-ref"); + log.debug("found " + mbeanRefElements.getLength() + " mbean-ref elements"); + for (int j = 0; j < mbeanRefElements.getLength(); j++) { + Element mbeanRefElement = (Element)mbeanRefElements.item(j); + String mbeanRefName = mbeanRefElement.getAttribute("name"); + if (!mbeanRefElement.hasChildNodes()) + { + throw new DeploymentException("No ObjectName supplied for mbean-ref " + mbeanRefName); + + } + // Get the mbeanRef value + String mbeanRefValue = ((Text)mbeanRefElement.getFirstChild()).getData().trim(); + ObjectName mbeanRefObjectName = new ObjectName(mbeanRefValue); + log.debug("considering " + mbeanRefName + " with object name " + mbeanRefObjectName); + MBeanAttributeInfo[] attributes = info.getAttributes(); + for (int k = 0; k < attributes.length; k++) { + if (mbeanRefName.equals(attributes[k].getName())) { + String typeName = attributes[k].getType(); + if (!"javax.management.ObjectName".equals(typeName)) + { + throw new DeploymentException("Trying to set " + mbeanRefName + " as an MBeanRef when it is not of type ObjectName"); + } // end of if () + if (!mBeanRefs.contains(mbeanRefObjectName)) + { + mBeanRefs.add(mbeanRefObjectName); + } // end of if () + + log.debug(mbeanRefName + " set to " + mbeanRefValue + " in " + objectName); + server.setAttribute(objectName, new Attribute(mbeanRefName, mbeanRefObjectName)); + + break; + } + } + + } + // Set lists of mbean references (object names) + + NodeList mbeanRefLists = mbeanElement.getElementsByTagName("mbean-ref-list"); + for (int j = 0; j < mbeanRefLists.getLength(); j++) { + Element mbeanRefListElement = (Element)mbeanRefLists.item(j); + String mbeanRefListName = mbeanRefListElement.getAttribute("name"); + + MBeanAttributeInfo[] attributes = info.getAttributes(); + for (int k = 0; k < attributes.length; k++) { + if (mbeanRefListName.equals(attributes[k].getName())) { + + NodeList mbeanRefList = mbeanRefListElement.getElementsByTagName("mbean-ref-list-element"); + ArrayList mbeanRefs = new ArrayList(); + for (int l = 0; l < mbeanRefList.getLength(); l++) + { + Element mbeanRefElement = (Element)mbeanRefList.item(l); + if (!mbeanRefElement.hasChildNodes()) + { + throw new DeploymentException("Empty mbean-ref-list-element!"); + } // end of if () + + // Get the mbeanRef value + String mbeanRefValue = ((Text)mbeanRefElement.getFirstChild()).getData().trim(); + ObjectName mbeanRefObjectName = new ObjectName(mbeanRefValue); + if (!mBeanRefs.contains(mbeanRefObjectName)) + { + mBeanRefs.add(mbeanRefObjectName); + } // end of if () + + } // end of for () + + log.debug(mbeanRefListName + " set to " + mbeanRefs + " in " + objectName); + server.setAttribute(objectName, new Attribute(mbeanRefListName, mbeanRefs)); + + break; + } + + } + } + return mBeanRefs; } /** 1.11 +244 -47 jboss/src/main/org/jboss/system/ServiceController.java Index: ServiceController.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/system/ServiceController.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- ServiceController.java 2001/10/20 11:12:32 1.10 +++ ServiceController.java 2001/11/10 21:38:06 1.11 @@ -5,6 +5,9 @@ * See terms of license at gnu.org. */ package org.jboss.system; + + + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @@ -13,13 +16,11 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; - import java.util.Map; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.JMRuntimeException; import javax.management.MBeanException; - import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanRegistration; @@ -30,8 +31,8 @@ import javax.management.RuntimeErrorException; import javax.management.RuntimeMBeanException; import javax.management.RuntimeOperationsException; - import org.w3c.dom.Element; +import javax.management.IntrospectionException; /** * This is the main Service Controller. A controller can deploy a service to a @@ -40,7 +41,7 @@ * @see org.jboss.system.Service * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">David Jencks</a> - * @version $Revision: 1.10 $ <p> + * @version $Revision: 1.11 $ <p> * * <b>Revisions:</b> <p> * @@ -64,8 +65,27 @@ * index into the ServiceProxy.hasOp array. */ private static HashMap serviceOpMap = new HashMap(); + /** + * Map between mbeans and the mbean references they have + */ + private static HashMap mbeanToMBeanRefsMap = new HashMap(); + //inverse map + private static HashMap mbeanRefToMBeansMap = new HashMap(); + + /** + * The set of mbeans that can't find all their mbean references, mapped to + * the mbeans they can't find. + */ + private static HashMap suspendedToMissingMBeanMap = new HashMap(); /** + * The map between missing mbeans and what is waiting for them : + * inverse of suspendedToMissingMBeanMap + */ + private static HashMap missingToSuspendedMBeanMap = new HashMap(); + + + /** * Helper classes to create and configure the classes */ protected ServiceCreator creator; @@ -80,7 +100,7 @@ MBeanServer server; /** The array list keeps the order of deployment. */ - List services = new ArrayList(); + List startedServices = new ArrayList(); /** The map keeps the list of objectNames to services. */ Map nameToServiceMap = new HashMap(); @@ -109,8 +129,8 @@ */ public ObjectName[] getDeployed() { - ObjectName[] deployed = new ObjectName[services.size()]; - services.toArray(deployed); + ObjectName[] deployed = new ObjectName[startedServices.size()]; + startedServices.toArray(deployed); return deployed; } @@ -139,8 +159,8 @@ { // The ObjectName of the bean ObjectName objectName = parseObjectName(mbeanElement); - - undeploy(objectName); + //at least make a new version! + //undeploy(objectName); // It is not there so really create the component now try @@ -179,35 +199,78 @@ } // Configure the MBean + boolean waiting = false; try { - configurator.configure(mbeanElement); + ArrayList mBeanRefs = configurator.configure(mbeanElement); + if (mBeanRefs.size() > 0) + { + synchronized (this) + { + mbeanToMBeanRefsMap.put(objectName, mBeanRefs); + //ArrayList waitingFor = new ArrayList(); + Iterator refs = mBeanRefs.iterator(); + while (refs.hasNext()) + { + //First, record dependencies + ObjectName ref = (ObjectName)refs.next(); + ArrayList backRefs = (ArrayList)mbeanRefToMBeansMap.get(ref); + if (backRefs == null) + { + backRefs = new ArrayList(); + mbeanRefToMBeansMap.put(ref, backRefs); + } // end of if () + if (!backRefs.contains(objectName)) + { + backRefs.add(objectName); + } // end of if () + //Now, does the needed mbean exist? if not, note suspension. + //We could use the mbean server or our own service map. + //if (!nameToServiceMap.containsKey(ref)) + if (!startedServices.contains(ref)) + { + //Not there, mark suspended. + markWaiting(ref, objectName); + } // end of if () + } // end of while () + } + + } // end of if (mBeanRefs.size() > 0) } catch (ConfigurationException e) { log.error("Could not configure MBean: " + objectName, e); throw e; } - String serviceFactory = mbeanElement.getAttribute("serviceFactory"); - - MBeanInfo info = server.getMBeanInfo(objectName); - - Service service = getServiceInstance(objectName, - server.getMBeanInfo(objectName), - mbeanElement.getAttribute("serviceFactory")); - - //Mbeans are init'ed and started by ServiceDeployer now. - - // we need to keep an order on the MBean it encapsulates dependencies - services.add(objectName); - // Keep track - nameToServiceMap.put(objectName, service); - - //You are done + registerAndStartService(objectName, serviceFactory); return objectName; } + //needs to be an mbean method, for e.g. RARDeployer to register RAR's for dependency. + //puts a mbean that you created some other way (such as deployed rar) + //into dependency system so other beans can be started/stopped on its + //existence (or registration) + public void registerAndStartService(ObjectName serviceName, String serviceFactory) throws Exception + { + try + { + Service service = getServiceInstance(serviceName, serviceFactory); + // Keep track + nameToServiceMap.put(serviceName, service); + + start(serviceName); + //You are done + } + catch (Exception e) + { + log.error("Problem in registerAndStartService", e); + //dont let anyone think we're started if we're not! + nameToServiceMap.remove(serviceName); + throw e; + } // end of try-catch + + } /** * #Description of the Method * @@ -229,7 +292,46 @@ */ public void undeploy(ObjectName objectName) throws Exception { + stop(objectName); + destroy(objectName); + //We are not needing anyone or waiting for anyone + ArrayList weNeededList = (ArrayList)mbeanToMBeanRefsMap.remove(objectName); + if (weNeededList != null) + { + //remove the back reference for each mbean we needed. + Iterator needed = weNeededList.iterator(); + while (needed.hasNext()) + { + ObjectName neededName = (ObjectName)needed.next(); + ArrayList needingList = (ArrayList)mbeanRefToMBeansMap.get(neededName); + if (needingList != null) + { + needingList.remove(objectName); + } // end of if () + + } // end of while () + + } // end of if () + + ArrayList weSuspendedForList = (ArrayList)suspendedToMissingMBeanMap.remove(objectName); + if (weSuspendedForList != null) + { + //remove the back reference for each mbean we suspended for. + Iterator suspendedFor = weSuspendedForList.iterator(); + while (suspendedFor.hasNext()) + { + ObjectName suspendedForName = (ObjectName)suspendedFor.next(); + ArrayList suspendedOnList = (ArrayList)missingToSuspendedMBeanMap.get(suspendedForName); + if (suspendedOnList != null) + { + suspendedOnList.remove(objectName); + } // end of if () + + } // end of while () + + } // end of if () + // Do we have a deployed MBean? if (server.isRegistered(objectName)) { @@ -238,7 +340,7 @@ } //Remove from local maps - services.remove(objectName); + startedServices.remove(objectName); Service service = (Service)nameToServiceMap.remove(objectName); // Remove the MBean from the MBeanServer @@ -281,6 +383,13 @@ return name == null ? new ObjectName(OBJECT_NAME) : name; } + // methods about suspension. + + public synchronized boolean isSuspended(ObjectName objectName) + { + return suspendedToMissingMBeanMap.containsKey(objectName); + } + // Service implementation ---------------------------------------- /** @@ -292,9 +401,9 @@ throws Exception { - log.info("Initializing " + services.size() + " services"); + log.info("Initializing " + startedServices.size() + " startedServices"); - List servicesCopy = new ArrayList(services); + List servicesCopy = new ArrayList(startedServices); Iterator enum = servicesCopy.iterator(); int serviceCounter = 0; ObjectName name = null; @@ -324,9 +433,9 @@ public void start() throws Exception { - log.info("Starting " + services.size() + " services"); + log.info("Starting " + startedServices.size() + " services"); - List servicesCopy = new ArrayList(services); + List servicesCopy = new ArrayList(startedServices); Iterator enum = servicesCopy.iterator(); int serviceCounter = 0; ObjectName name = null; @@ -349,13 +458,13 @@ } /** - * #Description of the Method + * This is the only one we should have of these lifecycle methods! */ public void stop() { - log.info("Stopping " + services.size() + " services"); + log.info("Stopping " + startedServices.size() + " services"); - List servicesCopy = new ArrayList(services); + List servicesCopy = new ArrayList(startedServices); ListIterator enum = servicesCopy.listIterator(); int serviceCounter = 0; ObjectName name = null; @@ -398,7 +507,7 @@ /* log.info("Destroying " + services.size() + " services"); - List servicesCopy = new ArrayList(services); + List servicesCopy = new ArrayList(startedServices); ListIterator enum = servicesCopy.listIterator(); int serviceCounter = 0; ObjectName name = null; @@ -435,16 +544,7 @@ */ public void init(ObjectName serviceName) throws Exception { - if (nameToServiceMap.containsKey(serviceName)) - { - - ((Service)nameToServiceMap.get(serviceName)).init(); - } - else - { - throw new InstanceNotFoundException - ("Could not find " + serviceName.toString()); - } + throw new Exception("init(serviceName) is obsolete"); } /** @@ -455,16 +555,58 @@ */ public void start(ObjectName serviceName) throws Exception { + if (suspendedToMissingMBeanMap.containsKey(serviceName)) + { + log.debug("waiting to start " + serviceName + " until dependencies are resolved"); + return; + } // end of if () + if (nameToServiceMap.containsKey(serviceName)) { + ((Service)nameToServiceMap.get(serviceName)).init(); ((Service)nameToServiceMap.get(serviceName)).start(); + startedServices.add(serviceName); } else { throw new InstanceNotFoundException ("Could not find " + serviceName.toString()); } + ArrayList waitingList = (ArrayList)missingToSuspendedMBeanMap.remove(serviceName); + if (waitingList != null) + { + Iterator waiting = waitingList.iterator(); + while (waiting.hasNext()) + { + ObjectName waitingName = (ObjectName)waiting.next(); + //Is it waiting for anyone else? + ArrayList waitingFor = (ArrayList)suspendedToMissingMBeanMap.get(waitingName); + if (waitingFor == null) + { + //maybe should be DeploymentException, but it might pull in too many classes. + throw new Exception("Missing suspended to Missing map entry between suspended: " + waitingName + " and missing: " + serviceName); + } // end of if () + waitingFor.remove(serviceName); + if (waitingFor.size() == 0) + { + //not waiting for anyone else, can finish deploying. + log.debug("missing mbeans now present, finishing deployment of " + waitingName); + suspendedToMissingMBeanMap.remove(waitingName); + //init(waitingName); + start(waitingName); + } // end of if () + else + { + log.debug("There are still missing mbeans, deployment of " + waitingName + " postponed"); + + } // end of else + + } // end of while () + + + } // end of if () + } /** @@ -475,6 +617,26 @@ */ public void stop(ObjectName serviceName) throws Exception { + ArrayList usingList = (ArrayList)mbeanRefToMBeansMap.get(serviceName); + if (usingList != null) + { + //we have to stop and destroy these beans that depend on serviceName. + Iterator using = usingList.iterator(); + while (using.hasNext()) + { + ObjectName usingName = (ObjectName)using.next(); + log.debug("stopping/destroying object " + usingName + " using " + serviceName); + if (!isWaitingFor(serviceName, usingName)) + { + markWaiting(serviceName, usingName); + stop(usingName); + destroy(usingName); + } // end of if () + + } // end of while () + + } // end of if () + if (nameToServiceMap.containsKey(serviceName)) { @@ -521,9 +683,8 @@ * @throws IllegalAccessException */ private Service getServiceInstance(ObjectName objectName, - MBeanInfo info, String serviceFactory) - throws ClassNotFoundException, InstantiationException, IllegalAccessException + throws ClassNotFoundException, InstantiationException, IllegalAccessException, JMException//, InstanceNotFoundException, IntrospectionException { Service service = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); @@ -535,6 +696,7 @@ } else { + MBeanInfo info = server.getMBeanInfo(objectName); MBeanOperationInfo[] opInfo = info.getOperations(); Class[] interfaces = {org.jboss.system.Service.class}; InvocationHandler handler = new ServiceProxy(objectName, opInfo); @@ -598,6 +760,41 @@ } e.printStackTrace(); log.error(e); + } + + private void markWaiting(ObjectName missing, ObjectName waiting) + { + ArrayList waitingList = (ArrayList)missingToSuspendedMBeanMap.get(missing); + if (waitingList == null) + { + waitingList = new ArrayList(); + missingToSuspendedMBeanMap.put(missing, waitingList); + } // end of if () + if (!waitingList.contains(waiting)) + { + waitingList.add(waiting); + } // end of if () + //Now do the other way. + ArrayList missingList = (ArrayList)suspendedToMissingMBeanMap.get(waiting); + if (missingList == null) + { + missingList = new ArrayList(); + suspendedToMissingMBeanMap.put(waiting, missingList); + } // end of if () + if (!missingList.contains(missing)) + { + missingList.add(missing); + } // end of if () + } + + private boolean isWaitingFor(ObjectName serviceName, ObjectName usingName) + { + ArrayList waitingList = (ArrayList)missingToSuspendedMBeanMap.get(serviceName); + if (waitingList == null) + { + return false;//noone is waiting for this guy. + } // end of if () + return waitingList.contains(usingName); } // Inner classes ------------------------------------------------- 1.3 +6 -1 jboss/src/main/org/jboss/system/ServiceControllerMBean.java Index: ServiceControllerMBean.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/system/ServiceControllerMBean.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ServiceControllerMBean.java 2001/09/08 00:53:57 1.2 +++ ServiceControllerMBean.java 2001/11/10 21:38:06 1.3 @@ -20,7 +20,7 @@ * @see Service * * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> - * @version $Revision: 1.2 $ + * @version $Revision: 1.3 $ * * <p><b>20010830 marc fleury:</b> * <ul> @@ -38,6 +38,11 @@ // ObjectName deploy(Element mbean) throws Exception; + + //puts a mbean that you created some other way (such as deployed rar) + //into dependency system so other beans can be started/stopped on its + //existence (or registration) + void registerAndStartService(ObjectName serviceName, String serviceFactory) throws Exception; void undeploy(Element mbean) throws Exception; void undeploy(ObjectName mbeanName) throws Exception; 1.7 +3 -46 jboss/src/main/org/jboss/system/URLClassLoader.java Index: URLClassLoader.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/system/URLClassLoader.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- URLClassLoader.java 2001/10/31 03:09:37 1.6 +++ URLClassLoader.java 2001/11/10 21:38:06 1.7 @@ -30,7 +30,7 @@ * * @author <a href="[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="[EMAIL PROTECTED]">Christoph G. Jung</a> - * @version $Revision: 1.6 $ + * @version $Revision: 1.7 $ * * <p><b>20010830 marc fleury:</b> * <ul> @@ -58,44 +58,7 @@ /** All SCL are just in orbit around a basic ServiceLibraries */ private static ServiceLibraries libraries; - /** - * One url per SCL - * - * @param String application - * @param ClassLoader parent - */ - /*public URLClassLoader( String pUrl ) - { - super( new URL[] {} ); - try - { - URL lUrl = new URL( pUrl ); - addURL( lUrl ); - this.keyUrl = lUrl; - } - catch( Exception e ) - { - System.out.println("[GPA] WARNING: URL "+keyUrl+" is not valid"); - } - - try - { - - //url.openStream(); - - - if (libraries == null) libraries = ServiceLibraries.getLibraries(); - - - // A URL enabled SCL must register itself with the libraries to be queried - libraries.addClassLoader(this); - } - catch(Exception e) - { - System.out.println("[GPA] WARNING: URL "+keyUrl+" could not be opened"); - } - }*/ - + /** * One url per SCL * @@ -106,21 +69,14 @@ { super(urls); this.keyUrl = keyUrl; - try { - //url.openStream(); if (libraries == null) { libraries = ServiceLibraries.getLibraries(); } - /* - //Reload the library if necessary - if (reload) - libraries.removeClassLoader(this) ; - */ // A URL enabled SCL must register itself with the libraries to // be queried @@ -172,6 +128,7 @@ { if (name.endsWith("CHANGEME")) { + System.out.println("UCL GETRESOURCE "+name+ " in UCL " + this.hashCode()); }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development