User: sparre  
  Date: 01/10/03 11:47:10

  Modified:    src/main/org/jboss/system ServiceLibraries.java
  Log:
  Changed synchronization to avoid deadlock with SUNs java.lang.ClassLoader
  implementation.
  
  Revision  Changes    Path
  1.5       +158 -148  jboss/src/main/org/jboss/system/ServiceLibraries.java
  
  Index: ServiceLibraries.java
  ===================================================================
  RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/system/ServiceLibraries.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ServiceLibraries.java     2001/09/26 21:47:05     1.4
  +++ ServiceLibraries.java     2001/10/03 18:47:10     1.5
  @@ -8,7 +8,6 @@
   
   import java.io.File;
   import java.net.URL;
  -import java.util.Collections;
   import java.util.HashMap;
   import java.util.HashSet;
   import java.util.Iterator;
  @@ -29,7 +28,8 @@
    *
    * @see <related>
    * @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
  - * @version $Revision: 1.4 $ <p>
  + * @author <a href="mailto:[EMAIL PROTECTED]";>Ole Husgaard</a>
  + * @version $Revision: 1.5 $ <p>
    *
    *      <b>20010830 marc fleury:</b>
    *      <ul>initial import
  @@ -38,6 +38,11 @@
    *      <b>20010908 david jencks:</b>
    *      <ul>Modified to make undeploy work better.
    *        <li>
  + *      <b>20011003 Ole Husgaard:</b>
  + *      <ul>Changed synchronization to avoid deadlock with SUNs
  + *          java.lang.Classloader implementation. Kudos to Dr. Christoph Jung
  + *          and Sacha Labourey for identifying this problem.
  + *        <li>
    *      </ul>
    *
    */
  @@ -51,19 +56,38 @@
   
      // Static --------------------------------------------------------
      private static ServiceLibraries libraries;
  +
      // Constants -----------------------------------------------------
   
      // Attributes ----------------------------------------------------
   
   
  -   // The classloaders
  +   /**
  +    *  The classloaders we use for loading classes here.
  +    */
      private Set classLoaders;
   
  -   // The classes kept in this library
  -   private Map classes, resources,
  -   // A given classloader loads a set of class
  -         clToClassSetMap, clToResourceSetMap;
  +   /*
  +    *  Maps class names of the classes loaded here to the classes.
  +    */
  +   private Map classes;
  +
  +   /*
  +    *  Maps class loaders to the set of classes they loaded here.
  +    */
  +   private Map clToClassSetMap;
   
  +   /*
  +    *  Maps resource names of resources looked up here to the URLs used to
  +    *  load them.
  +    */
  +   private Map resources;
  +
  +   /*
  +    *  Maps class loaders to the set of resource names they looked up here.
  +    */
  +   private Map clToResourceSetMap;
  +
      // Constructors --------------------------------------------------
   
      // Public --------------------------------------------------------
  @@ -76,9 +100,7 @@
      public static ServiceLibraries getLibraries()
      {
         if (libraries == null)
  -      {
            libraries = new ServiceLibraries();
  -      }
   
         return libraries;
      }
  @@ -86,7 +108,7 @@
      // ServiceClassLoaderMBean implementation ------------------------
   
      /**
  -    * Gets the Name attribute of the ServiceLibraries object
  +    * Gets the Name attribute of the ServiceLibraries object.
       *
       * @return The Name value
       */
  @@ -97,58 +119,56 @@
   
   
      /**
  -    * Gets the Resource attribute of the ServiceLibraries object
  +    *  Find a resource in the ServiceLibraries object.
       *
  -    * @param name Description of Parameter
  -    * @param scl Description of Parameter
  -    * @return The Resource value
  +    *  @param name The name of the resource
  +    *  @param scl The asking class loader
  +    *  @return An URL for reading the resource, or <code>null</code> if the
  +    *          resource could not be found.
       */
      public URL getResource(String name, ClassLoader scl)
      {
  -
  -      // Is it in the global map?
  -      if (resources.containsKey(name))
  -      {
  -
  -         return (URL)resources.get(name);
  +      Set classLoaders2;
  +      Map resources2;
  +      Map clToResourceSetMap2;
  +
  +      synchronized (this) {
  +         // Is it in the global map?
  +         if (resources.containsKey(name))
  +            return (URL)resources.get(name);
  +
  +         // No, make copies of the references to avoid working on or changing
  +         // a later version of these.
  +         classLoaders2 = classLoaders;
  +         resources2 = resources;
  +         clToResourceSetMap2 = clToResourceSetMap;
         }
   
         URL resource = null;
   
         // First ask for the class to the asking class loader
         if (scl instanceof URLClassLoader)
  -      {
            resource = ((URLClassLoader)scl).getResourceLocally(name);
  -      }
   
         if (resource == null)
         {
            // If not start asking around to URL classloaders for it
  -         int i = 1;
  -         synchronized (classLoaders)
  -         {
  -            Iterator allLoaders = classLoaders.iterator();
  -            while (allLoaders.hasNext())
  -            {
  -               URLClassLoader cl = (URLClassLoader)allLoaders.next();
  +         for (Iterator iter = classLoaders2.iterator(); iter.hasNext();) {
  +            URLClassLoader cl = (URLClassLoader)iter.next();
   
  -               if (!cl.equals(scl))
  -               {
  +            if (!cl.equals(scl)) { // already tried this one
  +               resource = cl.getResourceLocally(name);
   
  -                  resource = cl.getResourceLocally(name);
  -
  -                  if (resource != null)
  -                  {
  -
  +               if (resource != null) {
  +                  synchronized (this) {
                        // We can keep track
  -                     resources.put(name, resource);
  +                     resources2.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 set = (Set)clToResourceSetMap2.get(cl);
  +                     if (set == null) {
                           set = new HashSet();
  -                        clToResourceSetMap.put(cl, set);
  +                        clToResourceSetMap2.put(cl, set);
                        }
   
                        //set.add(resource);
  @@ -156,102 +176,110 @@
   
                        return resource;
                     }
  -                  //Just cycle through the class loaders until you find it
  -               }
  +               } // if we found it
               }
  -            //allLoaders
  -         }
  -         //Synchronization
  -      }
  -      // If we reach here, all of the classloaders currently in the VM don't know 
about the resource
  +         } // for all ClassLoaders
  +      } // If we reach here, all of the classloaders currently in the VM don't know 
about the resource
  +
         return resource;
      }
   
   
      /**
  -    * Adds a feature to the ClassLoader attribute of the ServiceLibraries object
  +    *  Add a ClassLoader to the ServiceLibraries object.
       *
  -    * @param cl The feature to be added to the ClassLoader attribute
  +    *  @param cl The class loader to be added.
       */
  -   public void addClassLoader(URLClassLoader cl)
  +   public synchronized void addClassLoader(URLClassLoader cl)
      {
  -      synchronized (classLoaders)
  -      {
  -
  -         // we allow for duplicate class loader definitions in the services.xml 
files
  -         // we should however only keep the first classloader declared
  +      // we allow for duplicate class loader definitions in the services.xml files
  +      // we should however only keep the first classloader declared
   
  -         if (!classLoaders.contains(cl))
  -         {
  -            classLoaders.add(cl);
  -            System.out.println("Libraries adding URLClassLoader " + cl.hashCode() + 
" key URL " + ((URLClassLoader)cl).getKeyURL().toString());
  -         }
  -         else
  -         {
  -            System.out.println("Libraries skipping duplicate URLClassLoader for key 
URL " + ((URLClassLoader)cl).getKeyURL().toString());
  -         }
  -      }
  +      if (!classLoaders.contains(cl)) {
  +         // We create a new copy of the classLoaders set.
  +         classLoaders = new HashSet(classLoaders);
  +
  +         classLoaders.add(cl);
  +
  +         System.out.println("Libraries adding URLClassLoader " + cl.hashCode() + " 
key URL " + ((URLClassLoader)cl).getKeyURL().toString());
  +      } else
  +         System.out.println("Libraries skipping duplicate URLClassLoader for key 
URL " + ((URLClassLoader)cl).getKeyURL().toString());
      }
   
      /**
  -    * #Description of the Method
  +    *  Remove a ClassLoader from the ServiceLibraries object.
       *
  -    * @param cl Description of Parameter
  +    *  @param cl The ClassLoader to be removed.
       */
  -   public void removeClassLoader(URLClassLoader cl)
  +   public synchronized void removeClassLoader(URLClassLoader cl)
      {
  -      synchronized (classLoaders)
  -      {
  -         System.out.println("removing classloader " + cl);
  +      System.out.println("removing classloader " + cl);
   
  -         classLoaders.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)) {
  +         // Create a new copy of the map
  +         clToClassSetMap = new HashMap(clToClassSetMap);
  +
            Set clClasses = (Set)clToClassSetMap.remove(cl);
  -         if (clClasses != null)
  -         {
  -            Iterator iterator = clClasses.iterator();
  -            while (iterator.hasNext())
  -            {
  -               Object o = iterator.next();
  -               Object o1 = classes.remove(o);
  -               System.out.println("removing class " + o + ", removed: " + o1);
  -            }
  +
  +         for (Iterator iter = clClasses.iterator(); iter.hasNext();) {
  +            Object o = iter.next();
  +            Object o1 = classes.remove(o);
  +            System.out.println("removing class " + o + ", removed: " + o1);
            }
  +      }
  +      
  +      // Same procedure for resources
  +      if (clToResourceSetMap.containsKey(cl)) {
  +         clToResourceSetMap = new HashMap(clToResourceSetMap);
   
            Set clResources = (Set)clToResourceSetMap.remove(cl);
  -         if (clResources != null)
  -         {
  -            Iterator iterator2 = clResources.iterator();
  -            while (iterator2.hasNext())
  -            {
  -               Object o = iterator2.next();
  -               Object o1 = resources.remove(o);
  -               System.out.println("removing resource " + o + ", removed: " + o1);
  -            }
  +
  +         for (Iterator iter = clResources.iterator(); iter.hasNext();) {
  +            Object o = iter.next();
  +            Object o1 = resources.remove(o);
  +            System.out.println("removing resource " + o + ", removed: " + o1);
            }
         }
  -      ;
      }
   
   
      /**
  -    * #Description of the Method
  +    *  Load a class in the ServiceLibraries object.
       *
  -    * @param name Description of Parameter
  -    * @param resolve Description of Parameter
  -    * @param scl Description of Parameter
  -    * @return Description of the Returned Value
  -    * @exception ClassNotFoundException Description of Exception
  +    *  @param name The name of the class
  +    *  @param resolve If <code>true</code>, the class will be resolved
  +    *  @param scl The asking class loader
  +    *  @return The loaded class.
  +    *          resource could not be found.
  +    *  @throws ClassNotFoundException If the class could not be found.
       */
      public Class loadClass(String name, boolean resolve, ClassLoader scl)
             throws ClassNotFoundException
      {
  -      // Try the local map already
  -      Class foundClass = (Class)classes.get(name);
  +      Class foundClass;
  +      Set classLoaders2;
  +      Map classes2;
  +      Map clToClassSetMap2;
  +
  +      synchronized (this) {
  +         // Try the local map already
  +         foundClass = (Class)classes.get(name);
   
  -      if (foundClass != null)
  -      {
  -         return foundClass;
  +         if (foundClass != null)
  +            return foundClass;
  +
  +         // Not found, make copies of the references to avoid working on
  +         // or changing a later version of these.
  +         classLoaders2 = classLoaders;
  +         classes2 = classes;
  +         clToClassSetMap2 = clToClassSetMap;
         }
   
         // If not start asking around to URL classloaders for it
  @@ -259,66 +287,49 @@
         // who will find it?
         URLClassLoader cl = null;
   
  -      if (scl instanceof URLClassLoader)
  -      {
  +      if (scl instanceof URLClassLoader) {
            // First ask the asking classloader chances are the dependent class is in 
there
  -         try
  -         {
  -
  +         try {
               foundClass = ((URLClassLoader)scl).loadClassLocally(name, resolve);
   
               //If we get here we know the scl is the right one
               cl = (URLClassLoader)scl;
  -         }
  -         catch (ClassNotFoundException ignored)
  -         {
  +         } catch (ClassNotFoundException ignored) {
            }
         }
  -
  -      synchronized (classLoaders)
  -      {
   
  -         Iterator allLoaders = classLoaders.iterator();
  -         while (allLoaders.hasNext() && (foundClass == null))
  -         {
  -            // next!
  -            cl = (URLClassLoader)allLoaders.next();
  -
  -            if (!scl.equals(cl))
  -            {
  -               try
  -               {
  -
  -                  foundClass = cl.loadClassLocally(name, resolve);
  -               }
  -               catch (ClassNotFoundException ignored2)
  -               {
  -                  //try next loader
  -               }
  +      Iterator allLoaders = classLoaders2.iterator();
  +      while (allLoaders.hasNext() && (foundClass == null)) {
  +         // next!
  +         cl = (URLClassLoader)allLoaders.next();
  +
  +         if (!scl.equals(cl)) {
  +            try {
  +               foundClass = cl.loadClassLocally(name, resolve);
  +            } catch (ClassNotFoundException ignored2) {
  +               //try next loader
               }
            }
  -         //allLoaders
  +      } //allLoaders
   
  -         if (foundClass != null)
  -         {
  +      if (foundClass != null) {
  +         synchronized (this) {
               // We can keep track
  -            classes.put(name, foundClass);
  +            classes2.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 set = (Set)clToClassSetMap2.get(cl);
  +            if (set == null) {
                  set = new HashSet();
  -               clToClassSetMap.put(cl, set);
  +               clToClassSetMap2.put(cl, set);
               }
   
               //set.add(foundClass);
               set.add(name);
  -
  -            return foundClass;
            }
  +
  +         return foundClass;
         }
  -      //Synchronization
   
         // If we reach here, all of the classloaders currently in the VM don't know 
about the class
         throw new ClassNotFoundException(name);
  @@ -338,14 +349,13 @@
      public ObjectName preRegister(MBeanServer server, ObjectName name)
             throws java.lang.Exception
      {
  -
         //this.server = server;
   
  -      classLoaders = Collections.synchronizedSet(new HashSet());
  -      classes = Collections.synchronizedMap(new HashMap());
  -      resources = Collections.synchronizedMap(new HashMap());
  -      clToResourceSetMap = Collections.synchronizedMap(new HashMap());
  -      clToClassSetMap = Collections.synchronizedMap(new HashMap());
  +      classLoaders = new HashSet();
  +      classes = new HashMap();
  +      resources = new HashMap();
  +      clToResourceSetMap = new HashMap();
  +      clToClassSetMap = new HashMap();
   
         System.out.println("[GPA] Microkernel ClassLoaders and Libraries 
initialized");
         return name == null ? new ObjectName(OBJECT_NAME) : name;
  
  
  

_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to