User: d_jencks Date: 02/04/03 18:17:22 Modified: src/main/org/jboss/system ServiceConfigurator.java ServiceController.java ServiceCreator.java ServiceLibraries.java Log: implemented automatic dependency management between mbeans and the classes their ObjectInstance indicates they require. ClassNotFoundException results in the deployment waiting until new classes are available. Undeploying classes undeploys mbeans known to be using them, saving the current configuration until the classes once again become available. Revision Changes Path 1.6 +122 -138 jboss-system/src/main/org/jboss/system/ServiceConfigurator.java Index: ServiceConfigurator.java =================================================================== RCS file: /cvsroot/jboss/jboss-system/src/main/org/jboss/system/ServiceConfigurator.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ServiceConfigurator.java 28 Mar 2002 03:13:35 -0000 1.5 +++ ServiceConfigurator.java 4 Apr 2002 02:17:22 -0000 1.6 @@ -54,13 +54,14 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; +import java.util.Iterator; /** * Service configuration helper. * * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Hiram Chirino</a> - * @version $Revision: 1.5 $ + * @version $Revision: 1.6 $ * * <p><b>20010830 marc fleury:</b> * <ul> @@ -127,21 +128,44 @@ List mbeans = new ArrayList(); try { - NodeList nl = config.getChildNodes(); - - for (int i = 0; i < nl.getLength(); i++) - { - if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) - { + if (config.getTagName().equals("mbean")) + { + try + { + internalInstall(config, mbeans); + } + catch (ClassNotFoundException cnfe) + { + //ignore + } - Element element = (Element)nl.item(i); - if (element.getTagName().equals("mbean")) + } + else + { + NodeList nl = config.getChildNodes(); + + for (int i = 0; i < nl.getLength(); i++) + { + if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) { - Element mbean = (Element)nl.item(i); - internalInstall(mbean, mbeans); - } // end of if () - } // end of if () - } + + Element element = (Element)nl.item(i); + if (element.getTagName().equals("mbean")) + { + Element mbean = (Element)nl.item(i); + try + { + internalInstall(mbean, mbeans); + } + catch (ClassNotFoundException cnfe) + { + //ignore + } + + } // end of if () + } // end of if () + }//end of for + } //end of else return mbeans; } catch (DeploymentException de) @@ -164,24 +188,31 @@ } // end of try-catch } - private ObjectName internalInstall(Element mbean, List mbeans) throws DeploymentException + private ObjectName internalInstall(Element mbeanElement, List mbeans) throws DeploymentException, ClassNotFoundException { - ObjectName mbeanName = null; + ObjectInstance instance = null; try { - mbeanName = serviceCreator.install(mbean).getObjectName(); + instance = serviceCreator.install(mbeanElement); + } + catch (ClassNotFoundException cnfe) + { + serviceController.registerWaitingForClass(mbeanElement); + throw cnfe; } catch (Exception e) { throw new DeploymentException("could not create mbean", e); } // end of catch + serviceController.registerMBeanClassName(instance); + ObjectName mbeanName = instance.getObjectName(); mbeans.add(mbeanName); if (mbeanName != null) { try { - configure(mbeanName, mbean, mbeans); + configure(mbeanName, mbeanElement, mbeans); serviceController.getServiceContext(mbeanName).state = ServiceContext.CONFIGURED; } catch (DeploymentException de) @@ -431,7 +462,14 @@ Element child = (Element)childNode; if (child.getTagName().equals("mbean")) { - dependsObjectName = internalInstall(child, mbeans); + try + { + dependsObjectName = internalInstall(child, mbeans); + } + catch (ClassNotFoundException cnfe) + { + log.info("FIX HANDLING OF ClassNotFound", cnfe); + } break; } else @@ -492,88 +530,6 @@ } // end of if () } - - /** - * Checks if an attribute of a given class is writtable. - * - * @param className The name of the class to check. - * @param attribute The name of the attribute to check. - * @param type The attribute type that the setter takes. - * - * @throws Exception Unable to determin if attribute is writable. - * @todo Remove this -- used only in obsolete listConfiguration method. - */ - private boolean isAttributeWriteable(final String className, - final String attribute, - final String type) - { - Class arg = null; - Class cls = null; - try - { - if (type.equals("int")) - arg = Integer.TYPE; - else if (type.equals("boolean")) - arg = Boolean.TYPE; - else if (type.equals("float")) - arg = Float.TYPE; - else if (type.equals("byte")) - arg = Byte.TYPE; - else if (type.equals("short")) - arg = Short.TYPE; - else if (type.equals("char")) - arg = Character.TYPE; - else if (type.equals("long")) - arg = Long.TYPE; - else if (type.equals("double")) - arg = Double.TYPE; - else - arg = Class.forName(type); - } catch (ClassNotFoundException e) - { - log.error("Unable to check parameter of type '" + type + "'"); - return false; - } - - try - { - cls = Class.forName(className); - } catch (ClassNotFoundException e) - { - log.error("Unable to check MBean of type '" + className + "'"); - return false; - } - - try - { - Method m = cls.getMethod("set" + attribute, new Class[] - { arg }); - return isSetterMethod(m); - } catch (NoSuchMethodException ignore) - {} - - return false; - } - - /** - * Check if the given method is a "setter" method. - * - * @param m The method to check. - * @return True if the method is a "setter" method. - * @todo Remove this -- used only in obsolete listConfiguration method. - */ - private boolean isSetterMethod(final Method m) - { - if (m != null) - { - return - Modifier.isPublic(m.getModifiers()) && - !Modifier.isStatic(m.getModifiers()) && - m.getReturnType().equals(Void.TYPE); - } - - return false; - } /** * Builds a string that consists of the configuration elements of @@ -598,43 +554,8 @@ // Store attributes as XML for (int j = 0 ; j<objectNames.length ; j++) { - ObjectInstance instance = server.getObjectInstance(objectNames[j]); - ObjectName name = (ObjectName)instance.getObjectName(); - Element mbeanElement = doc.createElement("mbean"); - mbeanElement.setAttribute("name", name.toString()); - - MBeanInfo info = server.getMBeanInfo(name); - mbeanElement.setAttribute("code", info.getClassName()); - MBeanAttributeInfo[] attributes = info.getAttributes(); - boolean hasAttributes = true; - for (int i = 0; i < attributes.length; i++) - { - if (attributes[i].isReadable() && isAttributeWriteable(server.getObjectInstance(name).getClassName(), attributes[i].getName(), attributes[i].getType())) - { - if (!attributes[i].isWritable()) - { - if (debug) - log.debug("Detected JMX Bug: Server reports attribute '"+attributes[i].getName() + "' is not writeable for MBean '" + name.getCanonicalName() + "'"); - } - Element attributeElement = doc.createElement("attribute"); - Object value = server.getAttribute(name, attributes[i].getName()); - - attributeElement.setAttribute("name", attributes[i].getName()); - - if (value != null) - { - attributeElement.appendChild(doc.createTextNode(value.toString())); - } - - mbeanElement.appendChild(attributeElement); - hasAttributes = true; - } - } - - if (hasAttributes) - { - serverElement.appendChild(mbeanElement); - } + Element mbeanElement = internalGetConfiguration(doc, objectNames[j]); + serverElement.appendChild(mbeanElement); } doc.appendChild(serverElement); @@ -648,5 +569,68 @@ return out.toString(); } + + Element getConfiguration(ObjectName name) throws Exception + { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.newDocument(); + return internalGetConfiguration(doc, name); + } + + private Element internalGetConfiguration(Document doc, ObjectName name) + throws Exception + { + Element mbeanElement = doc.createElement("mbean"); + mbeanElement.setAttribute("name", name.toString()); + + MBeanInfo info = server.getMBeanInfo(name); + mbeanElement.setAttribute("code", info.getClassName()); + MBeanAttributeInfo[] attributes = info.getAttributes(); + boolean hasAttributes = true; + for (int i = 0; i < attributes.length; i++) + { + log.trace("considering attribute: " + attributes[i]); + if (attributes[i].isReadable() && attributes[i].isWritable()) + { + Element attributeElement = null; + if (attributes[i].getType().equals("javax.management.ObjectName")) + { + attributeElement = doc.createElement("depends"); + attributeElement.setAttribute("optional-attribute-name", attributes[i].getName()); + } + else + { + attributeElement = doc.createElement("attribute"); + attributeElement.setAttribute("name", attributes[i].getName()); + } + Object value = server.getAttribute(name, attributes[i].getName()); + + if (value != null) + { + if (value instanceof Element) + { + attributeElement.appendChild(doc.importNode((Element)value, true)); + } + else + { + attributeElement.appendChild(doc.createTextNode(value.toString())); + } + } + + mbeanElement.appendChild(attributeElement); + + } + } + ServiceContext sc = serviceController.getServiceContext(name); + for (Iterator i = sc.iDependOn.iterator(); i.hasNext(); ) + { + ServiceContext needs = (ServiceContext)i.next(); + Element dependsElement = doc.createElement("depends"); + dependsElement.appendChild(doc.createTextNode(needs.objectName.toString())); + mbeanElement.appendChild(dependsElement); + } + return mbeanElement; + } } 1.6 +141 -12 jboss-system/src/main/org/jboss/system/ServiceController.java Index: ServiceController.java =================================================================== RCS file: /cvsroot/jboss/jboss-system/src/main/org/jboss/system/ServiceController.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ServiceController.java 24 Mar 2002 05:35:01 -0000 1.5 +++ ServiceController.java 4 Apr 2002 02:17:22 -0000 1.6 @@ -9,18 +9,23 @@ package org.jboss.system; + + + + + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; - import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.LinkedList; +import java.util.List; import java.util.ListIterator; import java.util.Map; - +import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.JMRuntimeException; @@ -30,14 +35,15 @@ import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationFilterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; import javax.management.ObjectName; - -import org.w3c.dom.Element; - import org.jboss.deployment.DeploymentException; import org.jboss.logging.Logger; - import org.jboss.util.jmx.JMXExceptionDecoder; +import org.w3c.dom.Element; /** * This is the main Service Controller. A controller can deploy a service to a @@ -47,7 +53,7 @@ * * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">David Jencks</a> - * @version $Revision: 1.5 $ <p> + * @version $Revision: 1.6 $ <p> * * <b>Revisions:</b> <p> * @@ -69,7 +75,7 @@ * @jmx:mbean name="jboss.system:service=ServiceController" */ public class ServiceController - implements ServiceControllerMBean, MBeanRegistration + implements ServiceControllerMBean, MBeanRegistration, NotificationListener { // Attributes ---------------------------------------------------- @@ -90,6 +96,20 @@ /** A linked list of services in the order they were created **/ protected List installedServices = new LinkedList(); + + /** + * A map of classname to list of mbeans whose class is from that + * classloader. + * + */ + private final Map classNameToMBeansMap = new HashMap(); + + /** + * <code>waitingConfigs</code> is the set of mbean configurations + * that cannot be deployed because the mbean class is not available. + * + */ + private Set waitingConfigs = new HashSet(); // Constructors -------------------------------------------------- @@ -135,6 +155,20 @@ { return configurator.getConfiguration(objectNames); } + + /** + * The <code>listWaitingMBeans</code> method returns a list + * of the mbeans currently not deployed because their classes + * are not available. + * + * @return a <code>List</code> value + * @exception Exception if an error occurs + * @jmx:managed-operation + */ + public List listWaitingMBeans() throws Exception + { + return new ArrayList(waitingConfigs); + } /** * Deploy the beans @@ -504,6 +538,14 @@ creator = new ServiceCreator(server); configurator = new ServiceConfigurator(server, this, creator); + + NotificationFilterSupport filter = new NotificationFilterSupport(); + filter.enableType(ServiceLibraries.CLASS_REMOVED_NOTIFICATION); + + server.addNotificationListener(ServiceLibrariesMBean.OBJECT_NAME, + this, + filter, + null); log.info("Controller MBean online"); return name == null ? OBJECT_NAME : name; @@ -520,6 +562,7 @@ public void preDeregister() throws Exception { + server.removeNotificationListener(ServiceLibrariesMBean.OBJECT_NAME, this); } public void postDeregister() @@ -532,9 +575,8 @@ * will be managed. * * @param objectName - * @param info * @param serviceFactory - * @return The ServiceInstance value + * @return The Service value * * @throws ClassNotFoundException * @throws InstantiationException @@ -580,7 +622,94 @@ return ctx; } - + + public synchronized void registerMBeanClassName(ObjectInstance instance) + { + String className = instance.getClassName(); + + Set mbeans = (Set)classNameToMBeansMap.get(className); + if (mbeans == null) + { + mbeans = new HashSet(); + classNameToMBeansMap.put(className, mbeans); + } + if (!mbeans.contains(instance.getObjectName())) + { + mbeans.add(instance.getObjectName()); + } + } + + public void handleNotification(Notification notification, Object handback) + { + String className = notification.getMessage(); + unregisterClassName(className); + } + + void unregisterClassName(String className) + { + Set mbeans = (Set)classNameToMBeansMap.remove(className); + if (mbeans != null) + { + for (Iterator i = mbeans.iterator(); i.hasNext(); ) + { + ObjectName mbeanName = (ObjectName)i.next(); + try + { + Element mbeanConfig = configurator.getConfiguration(mbeanName); + stop(mbeanName); + destroy(mbeanName); + remove(mbeanName); + registerWaitingForClass(mbeanConfig); + } + catch (Exception e) + { + log.info("Exception removing mbean: " + mbeanName, e); + } + } + } + } + + synchronized void registerWaitingForClass(Element mbeanElement) + { + log.trace("registering waiting for class: " + mbeanElement); + waitingConfigs.add(mbeanElement); + } + + /** + * Describe <code>newClassLoaderNotification</code> method here. + * @jmx:managed-operation + */ + public void newClassLoaderNotification() + { + log.trace("Scanning for newly supplied classes for waiting mbeans"); + Set waiting = null; + synchronized (this) + { + waiting = waitingConfigs; + waitingConfigs = new HashSet(); + } + for (Iterator i = waiting.iterator(); i.hasNext(); ) + { + Element mbeanElement = (Element)i.next(); + try + { + log.trace("trying to install mbean: " + mbeanElement); + List mbeans = configurator.install(mbeanElement); + for (Iterator j = mbeans.iterator(); j.hasNext(); ) + { + ObjectName name = (ObjectName)j.next(); + create(name); + start(name); + } + } + catch (Exception e) + { + log.info("Exception when trying to deploy waiting mbean" + mbeanElement, e); + } + } + } + + // Inner classes ------------------------------------------------- /** 1.2 +9 -1 jboss-system/src/main/org/jboss/system/ServiceCreator.java Index: ServiceCreator.java =================================================================== RCS file: /cvsroot/jboss/jboss-system/src/main/org/jboss/system/ServiceCreator.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ServiceCreator.java 24 Feb 2002 10:24:34 -0000 1.1 +++ ServiceCreator.java 4 Apr 2002 02:17:22 -0000 1.2 @@ -17,6 +17,7 @@ import javax.management.MalformedObjectNameException; import org.jboss.logging.Logger; +import org.jboss.util.jmx.JMXExceptionDecoder; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -27,7 +28,7 @@ * @see Service * * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> - * @version $Revision: 1.1 $ + * @version $Revision: 1.2 $ * * <p><b>Revisions:</b> * <p><b>2001/08/03 marcf </b> @@ -107,6 +108,13 @@ } catch (Exception e) { + Throwable newE = JMXExceptionDecoder.decode(e); + if (newE instanceof ClassNotFoundException) + { + log.debug("Class not found for mbean: " + name); + throw (ClassNotFoundException)newE; + } + // didn't work, unregister in case the jmx agent is screwed. try { 1.3 +297 -216 jboss-system/src/main/org/jboss/system/ServiceLibraries.java Index: ServiceLibraries.java =================================================================== RCS file: /cvsroot/jboss/jboss-system/src/main/org/jboss/system/ServiceLibraries.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ServiceLibraries.java 27 Feb 2002 18:56:10 -0000 1.2 +++ ServiceLibraries.java 4 Apr 2002 02:17:22 -0000 1.3 @@ -9,18 +9,25 @@ package org.jboss.system; -import java.net.URL; + + +import java.net.URL; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.Map; import java.util.Set; - +import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; import javax.management.ObjectName; - import org.jboss.logging.Logger; /** @@ -30,7 +37,7 @@ * @see <related> * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a> * @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a> - * @version $Revision: 1.2 $ <p> + * @version $Revision: 1.3 $ <p> * * <p><b>20010830 marc fleury:</b> * <ul> @@ -57,8 +64,10 @@ * @todo: track automate dependencies through UCL loading */ public class ServiceLibraries - implements ServiceLibrariesMBean, MBeanRegistration + implements ServiceLibrariesMBean, MBeanRegistration, NotificationBroadcaster { + + public static final String CLASS_REMOVED_NOTIFICATION = "jboss.system.classremoved"; /** Class logger */ private static final Logger log = Logger.getLogger(ServiceLibraries.class); @@ -70,7 +79,8 @@ // Attributes ---------------------------------------------------- - + private long sequenceId = 0; + /** * The classloaders we use for loading classes here. */ @@ -116,6 +126,10 @@ * the class is still in the {@link #classLoaders} set. */ private long clToResourceSetMapVersion = 0; + + private Map listeners = new HashMap(); + + private MBeanNotificationInfo[] info; // Constructors -------------------------------------------------- @@ -168,62 +182,62 @@ if (resource != null) return resource; synchronized (this) - { - // Is it in the global map? - if (resources.containsKey(name)) - return (URL)resources.get(name); - - // No, make copies of the classLoader reference to avoid working on - // a later version of it. - classLoaders2 = classLoaders; - - // Save the current version of the resource map, so we - // can detect if it has changed. - clToResourceSetMapVersion2 = clToResourceSetMapVersion; - } + { + // Is it in the global map? + if (resources.containsKey(name)) + return (URL)resources.get(name); + + // No, make copies of the classLoader reference to avoid working on + // a later version of it. + classLoaders2 = classLoaders; + + // Save the current version of the resource map, so we + // can detect if it has changed. + clToResourceSetMapVersion2 = clToResourceSetMapVersion; + } // If not start asking around to URL classloaders for it for (Iterator iter = classLoaders2.iterator(); iter.hasNext();) - { - UnifiedClassLoader cl = (UnifiedClassLoader)iter.next(); + { + UnifiedClassLoader cl = (UnifiedClassLoader)iter.next(); - if (!cl.equals(scl)) - { // already tried this one - resource = cl.getResourceLocally(name); + if (!cl.equals(scl)) + { // already tried this one + resource = cl.getResourceLocally(name); - if (resource != null) - { - synchronized (this) - { - // Did the version change? - if (clToResourceSetMapVersion2 != clToResourceSetMapVersion) - { - // Yes. Is the class loader we used still here? - if (!classLoaders.contains(cl)) - { - // No, it was removed from under us. - // Don't change the maps, simply return the resource. - return resource; - } - } - // We can keep track - resources.put(name, resource); + if (resource != null) + { + synchronized (this) + { + // Did the version change? + if (clToResourceSetMapVersion2 != clToResourceSetMapVersion) + { + // Yes. Is the class loader we used still here? + if (!classLoaders.contains(cl)) + { + // No, it was removed from under us. + // Don't change the maps, simply return the resource. + return resource; + } + } + // We can keep track + resources.put(name, resource); - // When we cycle the cl we also need to remove the classes it loaded - Set set = (Set)clToResourceSetMap.get(cl); - if (set == null) - { - set = new HashSet(); - clToResourceSetMap.put(cl, set); - } + // When we cycle the cl we also need to remove the classes it loaded + Set set = (Set)clToResourceSetMap.get(cl); + if (set == null) + { + set = new HashSet(); + clToResourceSetMap.put(cl, set); + } - set.add(name); + set.add(name); - return resource; - } - } // if we found it - } - } + return resource; + } + } // if we found it + } + } // for all ClassLoaders, If we reach here, all of the classloaders currently in the VM // don't know about the resource @@ -242,22 +256,22 @@ // we should however only keep the first classloader declared boolean trace = log.isTraceEnabled(); if (!classLoaders.contains(cl)) - { - // We create a new copy of the classLoaders set. - classLoaders = new HashSet(classLoaders); - - classLoaders.add(cl); - if( trace ) - { - log.trace("Libraries adding UnifiedClassLoader " + cl.hashCode() + - " key URL " + cl.getURL().toString()); - } - } + { + // We create a new copy of the classLoaders set. + classLoaders = new HashSet(classLoaders); + + classLoaders.add(cl); + if( trace ) + { + log.trace("Libraries adding UnifiedClassLoader " + cl.hashCode() + + " key URL " + cl.getURL().toString()); + } + } else if( trace ) - { - log.trace("Libraries skipping duplicate UnifiedClassLoader for key URL " + - cl.getURL().toString()); - } + { + log.trace("Libraries skipping duplicate UnifiedClassLoader for key URL " + + cl.getURL().toString()); + } } /** @@ -265,50 +279,72 @@ * * @param cl The ClassLoader to be removed. */ - public synchronized void removeClassLoader(UnifiedClassLoader cl) + public void removeClassLoader(UnifiedClassLoader cl) { boolean trace = log.isTraceEnabled(); - if( trace ) - log.trace("removing classloader " + cl); - - if (!classLoaders.contains(cl)) - return; // nothing to remove - - // We create a new copy of the classLoaders set. - classLoaders = new HashSet(classLoaders); - classLoaders.remove(cl); - - if (clToClassSetMap.containsKey(cl)) + if (trace) { - // We have a new version of the map - ++clToClassSetMapVersion; - - Set clClasses = (Set)clToClassSetMap.remove(cl); - - for (Iterator iter = clClasses.iterator(); iter.hasNext();) - { - Object o = iter.next(); - Object o1 = classes.remove(o); - if( trace ) - log.trace("removing class " + o + ", removed: " + o1); - } + log.trace("removing classloader " + cl); } - - // Same procedure for resources - if (clToResourceSetMap.containsKey(cl)) + Set clClasses = null; + synchronized (this) { - ++clToResourceSetMapVersion; - - Set clResources = (Set)clToResourceSetMap.remove(cl); + if (!classLoaders.contains(cl)) + { + return; // nothing to remove + } + // We create a new copy of the classLoaders set. + classLoaders = new HashSet(classLoaders); + classLoaders.remove(cl); + + if (clToClassSetMap.containsKey(cl)) + { + // We have a new version of the map + ++clToClassSetMapVersion; + + clClasses = (Set)clToClassSetMap.remove(cl); + } + }//synchronized + + if (clClasses != null) + { + for (Iterator i = clClasses.iterator(); i.hasNext(); ) + { + notify(CLASS_REMOVED_NOTIFICATION, (String)i.next()); + } + synchronized (this) + { - for (Iterator iter = clResources.iterator(); iter.hasNext();) - { - Object o = iter.next(); - Object o1 = resources.remove(o); - if( trace ) - log.trace("removing resource " + o + ", removed: " + o1); - } - } + for (Iterator iter = clClasses.iterator(); iter.hasNext();) + { + Object o = iter.next(); + Object o1 = classes.remove(o); + + if (trace) + { + log.trace("removing class " + o + ", removed: " + o1); + } + } + } + + // Same procedure for resources + if (clToResourceSetMap.containsKey(cl)) + { + ++clToResourceSetMapVersion; + + Set clResources = (Set)clToResourceSetMap.remove(cl); + + for (Iterator iter = clResources.iterator(); iter.hasNext();) + { + Object o = iter.next(); + Object o1 = resources.remove(o); + if (trace) + { + log.trace("removing resource " + o + ", removed: " + o1); + } + } + }//synchronized + }//if } /** @@ -329,93 +365,93 @@ long clToClassSetMapVersion2; synchronized (this) - { - // Try the local map already - foundClass = (Class)classes.get(name); - - if (foundClass != null) - return foundClass; - - // Not found, make copies of the classLoader reference to avoid - // working on a later version of it. - classLoaders2 = classLoaders; - - // Save the current version of the class map, so we - // can detect if it has changed. - clToClassSetMapVersion2 = clToClassSetMapVersion; - } + { + // Try the local map already + foundClass = (Class)classes.get(name); + + if (foundClass != null) + return foundClass; + + // Not found, make copies of the classLoader reference to avoid + // working on a later version of it. + classLoaders2 = classLoaders; + + // Save the current version of the class map, so we + // can detect if it has changed. + clToClassSetMapVersion2 = clToClassSetMapVersion; + } // If not start asking around to URL classloaders for it // who will find it? UnifiedClassLoader cl = null; if (scl instanceof UnifiedClassLoader) - { - // First ask the asking classloader chances are the dependent class is in there - try - { - foundClass = ((UnifiedClassLoader)scl).loadClassLocally(name, resolve); + { + // First ask the asking classloader chances are the dependent class is in there + try + { + foundClass = ((UnifiedClassLoader)scl).loadClassLocally(name, resolve); - //If we get here we know the scl is the right one - cl = (UnifiedClassLoader)scl; - } - catch (ClassNotFoundException ignored) - { - } - } + //If we get here we know the scl is the right one + cl = (UnifiedClassLoader)scl; + } + catch (ClassNotFoundException ignored) + { + } + } if (foundClass == null) - { - Iterator allLoaders = classLoaders2.iterator(); - while (allLoaders.hasNext() && (foundClass == null)) - { - // next! - cl = (UnifiedClassLoader)allLoaders.next(); - - if (!scl.equals(cl)) - { - try - { - foundClass = cl.loadClassLocally(name, resolve); - } - catch (ClassNotFoundException ignored2) - { - //try next loader - } - } - } //allLoaders - } + { + Iterator allLoaders = classLoaders2.iterator(); + while (allLoaders.hasNext() && (foundClass == null)) + { + // next! + cl = (UnifiedClassLoader)allLoaders.next(); + + if (!scl.equals(cl)) + { + try + { + foundClass = cl.loadClassLocally(name, resolve); + } + catch (ClassNotFoundException ignored2) + { + //try next loader + } + } + } //allLoaders + } if (foundClass != null) - { - synchronized (this) - { - // Did the version change? - if (clToClassSetMapVersion2 != clToClassSetMapVersion) - { - // Yes. Is the class loader we used still here? - if (!classLoaders.contains(cl)) - { - // No, it was removed from under us. - // Don't change the maps, simply return the class. - return foundClass; - } - } - // We can keep track - classes.put(name, foundClass); + { + synchronized (this) + { + // Did the version change? + if (clToClassSetMapVersion2 != clToClassSetMapVersion) + { + // Yes. Is the class loader we used still here? + if (!classLoaders.contains(cl)) + { + // No, it was removed from under us. + // Don't change the maps, simply return the class. + return foundClass; + } + } + // We can keep track + classes.put(name, foundClass); - // When we cycle the cl we also need to remove the classes it loaded - Set set = (Set)clToClassSetMap.get(cl); - if (set == null) - { - set = new HashSet(); - clToClassSetMap.put(cl, set); - } - set.add(name); - } + // When we cycle the cl we also need to remove the classes it loaded + Set set = (Set)clToClassSetMap.get(cl); + if (set == null) + { + set = new HashSet(); + clToClassSetMap.put(cl, set); + } + set.add(name); + } - return foundClass; - } + return foundClass; + } // If we reach here, all of the classloaders currently in the VM don't know about the class @@ -423,38 +459,38 @@ } /** Iterates through the current class loaders and tries to find the - given class name. - @return the Class object for name if found, null otherwise. - */ + given class name. + @return the Class object for name if found, null otherwise. + */ public Class findClass(String name) { Class clazz = null; Set classLoaders2; synchronized (this) - { - classLoaders2 = classLoaders; - } + { + classLoaders2 = classLoaders; + } /* We have to find the class as a resource as we don't want to invoke loadClass(name) and cause the side-effect of loading new classes. */ String classRsrcName = name.replace('.', '/') + ".class"; for(Iterator iter = classLoaders2.iterator(); iter.hasNext();) - { - UnifiedClassLoader cl = (UnifiedClassLoader)iter.next(); - URL classURL = cl.getResource(classRsrcName); - if( classURL != null ) - { - try - { - // Since the class was found we can load it which should be a noop - clazz = cl.loadClass(name); - } - catch(ClassNotFoundException e) - { - log.debug("Failed to load class: "+name, e); - } - } - } + { + UnifiedClassLoader cl = (UnifiedClassLoader)iter.next(); + URL classURL = cl.getResource(classRsrcName); + if( classURL != null ) + { + try + { + // Since the class was found we can load it which should be a noop + clazz = cl.loadClass(name); + } + catch(ClassNotFoundException e) + { + log.debug("Failed to load class: "+name, e); + } + } + } return clazz; } @@ -466,21 +502,21 @@ HashSet classpath = new HashSet(); Set classLoaders2; synchronized (this) - { - classLoaders2 = classLoaders; - } + { + classLoaders2 = classLoaders; + } for (Iterator iter = classLoaders2.iterator(); iter.hasNext();) - { - UnifiedClassLoader cl = (UnifiedClassLoader)iter.next(); - URL[] urls = cl.getClasspath(); - int length = urls != null ? urls.length : 0; - for(int u = 0; u < length; u ++) - { - URL path = urls[u]; - classpath.add(path); - } - } // for all ClassLoaders + { + UnifiedClassLoader cl = (UnifiedClassLoader)iter.next(); + URL[] urls = cl.getClasspath(); + int length = urls != null ? urls.length : 0; + for(int u = 0; u < length; u ++) + { + URL path = urls[u]; + classpath.add(path); + } + } // for all ClassLoaders URL[] urls = new URL[classpath.size()]; classpath.toArray(urls); @@ -540,4 +576,49 @@ { // empty } + + //NotificationBroadcaster implementation + + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) + { + listeners.put(listener, handback); + } + + public void removeNotificationListener(NotificationListener listener) + { + listeners.remove(listener); + } + + public MBeanNotificationInfo[] getNotificationInfo() + { + if (info == null) + { + info = new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] {"CLASS_REMOVED_NOTIFICATION"}, + "javax.management.Notification", + "Notification that a class has been removed from the extensible classloader") + + }; + } + return info; + } + + private void notify(String notificationType, String message) + { + Notification notification = new Notification(CLASS_REMOVED_NOTIFICATION, + this, + getSequenceId(), + message); + for (Iterator i = listeners.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry)i.next(); + ((NotificationListener)entry.getKey()).handleNotification(notification, entry.getValue()); + } + } + + private synchronized long getSequenceId() + { + return sequenceId++; + } + }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development