User: juhalindfors
  Date: 02/03/17 02:30:31

  Added:       src/main/org/jboss/mx/loading UnifiedClassLoader.java
                        UnifiedLoaderRepository.java
  Log:
  Unified class loader integration. Maybe still a bit flaky, but can handle
  at least the basic test -- two MLet loaders loading the same class definition
  only once and avoid a conflicting class definition.
  
  Revision  Changes    Path
  1.1                  jmx/src/main/org/jboss/mx/loading/UnifiedClassLoader.java
  
  Index: UnifiedClassLoader.java
  ===================================================================
  /***************************************
   *                                     *
   *  JBoss: The OpenSource J2EE WebOS   *
   *                                     *
   *  Distributable under LGPL license.  *
   *  See terms of license at gnu.org.   *
   *                                     *
   ***************************************/
  
  package org.jboss.mx.loading;
  
  import java.net.URL;
  import java.net.URLClassLoader;
  
  import java.io.InputStream;
  
  import java.util.Map;
  
  import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
  
  /**
   * A ClassLoader which loads classes from a single URL in conjunction with
   * the {@link UnifiedLoaderRepository}. Notice that this classloader does
   * not work independently without the repository. A repository reference
   * must be provided via the constructor or the classloader must be explicitly
   * registered to the repository before any attempt to load a class.
   * 
   * @author <a href="[EMAIL PROTECTED]">Marc Fleury</a>
   * @author <a href="[EMAIL PROTECTED]">Christoph G. Jung</a>
   * @author <a href="[EMAIL PROTECTED]">Scott Stark</a>
   * @author <a href="[EMAIL PROTECTED]">Juha Lindfors</a>
   * @version <tt>$Revision: 1.1 $</tt>
   * 
   * <p><b>20010830 marc fleury:</b>
   * <ul>
   *   <li>Initial import
   * </ul>
   *
   * <p><b>20011009 cgj:</b>
   * <ul>
   *   <li>fixed default resolution behaviour
   * </ul>
   *
   * <p><b>20020315 Juha Lindfors:</b>
   * <ul>
   *  <li> Support for adding your own class definitions instead of just an URL.</li>
   *
   *  <li> Removed static reference to repository. This is now set as the classloader
   *       is registered to the repository via setRepository() call.
   *  </li>
   */
  public class UnifiedClassLoader
     extends URLClassLoader
  {
  
     // Attributes ----------------------------------------------------
     
     /** Reference to the unified repository. */
     private UnifiedLoaderRepository repository = null;
     
     /** One URL per ClassLoader in our case */   
     private URL url = null;
     
     /** Class definitions */
     private Map classes = new ConcurrentReaderHashMap();
     
     // Constructors --------------------------------------------------
     /**
      * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
      * classloader repository.
      *
      * @param url   the single URL to load classes from.
      */
     public UnifiedClassLoader(URL url)
     {
        super(new URL[] {url}, UnifiedClassLoader.class.getClassLoader());
        
        // FIXME: log it
        System.out.println("New UCL with url " + url);
        
        this.url = url;
     }
  
     /**
      * Construct a <tt>UnifiedClassLoader</tt> and registers it to the given
      * repository.
      *
      * @param   url   The single URL to load classes from.
      * @param   repository the repository this classloader delegates to
      */
     public UnifiedClassLoader(URL url, UnifiedLoaderRepository repository)
     {
        this(url);
        
        // set the repository reference
        this.repository = repository;
  
        // register this loader to the given repository
        repository.addClassLoader(this);
     }
  
     /**
      * Constructs a <tt>UnifiedClassLoader</tt> with given class definition.
      *
      * @param   names class name
      * @param   codes class definition
      */
     public UnifiedClassLoader(String name, byte[] code)
     {
        // FIXME: UCL cloader or ctx cl as parent??
        super(new URL[] {}, UnifiedClassLoader.class.getClassLoader());
        addClass(name, code); 
     }
     
     
     // Public --------------------------------------------------------
     public void addClass(String name, byte[] code)
     {
        classes.put(name, code);
     }
     
     public void setRepository(UnifiedLoaderRepository repository)
     {
        this.repository = repository;
     }
  
     /**
      */
     public Class loadClassLocally(String name, boolean resolve)
        throws ClassNotFoundException
     {
        // check our own class definitions foist, then delegate to parent
        Object o = classes.get(name);
        
        if (o != null)
        {
           byte[] code = (byte[])o;
           return defineClass(name, code, 0, code.length);
        }
        
        else
        {
           return super.loadClass(name, resolve);
        }
     }
  
     /**
      * Provides the same functionality as {@link java.net.URLClassLoader#getResource}.
      */
     public URL getResourceLocally(String name)
     {
        return super.getResource(name);
     }
  
     /**
      */
     public URL getURL() {
        return url;
     }
  
     /**
      * This method simply invokes the super.getURLs() method to access the
      * list of URLs that make up the UnifiedClassLoader classpath.
      */
     public URL[] getClasspath()
     {
        return super.getURLs();
     }
     
     // URLClassLoader overrides --------------------------------------
     
     /**
      * We intercept the load class to know exactly the dependencies
      * of the underlying jar.
      *
      * <p>Forwards request to {@link UnifiedLoaderRepository}.
      */
     public Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
     {
        return repository.loadClass(name, resolve, this);  
     }
  
     /**
      * Attempts to load the resource from its URL and if not found
      * forwards to the request to {@link UnifiedLoaderRepository}.
      */
     public URL getResource(String name)
     {
        URL resource = super.getResource(name);
        
        if (resource == null)
        {
           resource = repository.getResource(name, this);
        }
        
        // if (resource == null)
        // {
        //    if (log.isTraceEnabled())
        //       log.trace("Did not find the UCL resource: " + name);
        // }
  
        return resource;
     }
  
     /**
      */
     public int hashCode() 
     {
        // FIXME: right now we don't care about not hitting the same slot in case
        //        of our own class definitions (as it's only used for optimized
        //        dispatchers and those are never shared).
        return (url == null) ? classes.hashCode() : url.hashCode();
     }
  
     /**
      */
     public boolean equals(Object other) 
     {
        if (other instanceof UnifiedClassLoader) 
        {
           // FIXME: currently ignores equals check for instances that contain
           //        their own class definitions. We're using this only for
           //        optimized dispatcher classes and they're never equal
           URL url2 = ((UnifiedClassLoader)other).getURL();
           return (url2 == null) ? false : url2.equals(url);
        }
        return false;
     }
  
     /**
      * Return an empty URL array to force the RMI marshalling subsystem to
      * use the <tt>java.server.codebase</tt> property as the annotated codebase.
      *
      * <p>Do not remove this method without discussing it on the dev list.
      *
      * @return Empty URL[]
      */
     public URL[] getURLs()
     {
        return EMPTY_URL_ARRAY;
     }
  
     /** The value returned by {@link getURLs}. */
     private static final URL[] EMPTY_URL_ARRAY = {};
  
  
     /**
      * Retruns a string representaion of this UCL.
      */
     public String toString()
     {
        return super.toString() + "{ url=" + getURL() + " }";
     }
  }
  
  
  
  
  1.1                  jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepository.java
  
  Index: UnifiedLoaderRepository.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.mx.loading;
  
  import java.util.Set;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import java.net.URL;
  import java.net.URLClassLoader;
  
  import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
  
  
  /**
   * <description> 
   *
   * @see <related>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
   * @author <a href="mailto:[EMAIL PROTECTED]";>Ole Husgaard</a>
   * @author  <a href="mailto:[EMAIL PROTECTED]";>Juha Lindfors</a>.
   * @version $Revision: 1.1 $
   *   
   */
  public class UnifiedLoaderRepository
     extends LoaderRepository
  {
     
     // Attributes ----------------------------------------------------
     
     /**
      * The classloaders we use for loading classes here.
      */
     private Set classLoaders       = new HashSet();
     
     /**
      * Maps class names of the classes loaded here to the classes.
      */
     private Map classes            = new HashMap();
     
     /**
      * Maps class loaders to the set of classes they loaded here.
      */
     private Map clToClassSetMap    = new HashMap();
     
     /**
      * The version number of the {@link #clToClassSetMap} map.
      * If a lookup of a class detects a change in this while calling
      * the classloaders with locks removed, the {@link #clToClassSetMap}
      * and {@link #classes} fields should <em>only</em> be modified
      * if the classloader used for loading the class is still in the
      * {@link #classLoaders} set.
      */
     private long clToClassSetMapVersion = 0;
     
     /**
      * Maps resource names of resources looked up here to the URLs used to
      * load them.
      */
     private Map resources          = new HashMap();
     
     /**
      * Maps class loaders to the set of resource names they looked up here.
      */
     private Map clToResourceSetMap = new HashMap();
     
     /**
      * The version number of the {@link #clToResourceSetMap} map.
      * If a lookup of a resource detects a change in this while
      * calling the classloaders with locks removed, the
      * {@link #clToResourceSetMap} and {@link #resources} fields should
      * <em>only</em> be modified if the classloader used for loading
      * the class is still in the {@link #classLoaders} set.
      */
     private long clToResourceSetMapVersion = 0;
  
     
     // Public --------------------------------------------------------
     /**
      * Add a class to this repository. Allows a class to be added in
      * byte code form stored inside this repository.
     /**
      * Load a class in this repository.
      *
      * @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
     {
        Class foundClass;
        Set classLoaders2;
        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;
        }
        
        // 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);
              
              //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
        }
        
        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);
              
              // 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;
        }
        
        // If we reach here, all of the classloaders currently in the VM don't know 
about the class
  
        throw new ClassNotFoundException(name);
     }
  
     /**
      * Find a resource from this repository.
      *
      * @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)
     {
        Set classLoaders2;
        long clToResourceSetMapVersion2;
        
        URL resource = null;
        
        // First ask for the class to the asking class loader
        if (scl instanceof UnifiedClassLoader)
           resource = ((UnifiedClassLoader)scl).getResourceLocally(name);
        
        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;
        }
        
        // If not start asking around to URL classloaders for it
        for (Iterator iter = classLoaders2.iterator(); iter.hasNext();)
        {
           UnifiedClassLoader cl = (UnifiedClassLoader)iter.next();
           
           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);
                    
                    // 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);
                    
                    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
        
        return resource;
     }
  
     /** Iterates through the current class loaders and tries to find the
      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;
        }
        /* 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)
              {
                 System.out.println("Failed to load class: "+name+ "\n" +e.toString());
                 //log.debug("Failed to load class: "+name, e);
              }
           }
        }
        return clazz;
     }
  
     /** Obtain a listing of the URL for all UnifiedClassLoaders associated with
      *the ServiceLibraries
      */
     public URL[] getURLs()
     {
        HashSet classpath = new HashSet();
        Set classLoaders2;      
        synchronized (this)
        {
           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
  
        URL[] urls = new URL[classpath.size()];
        classpath.toArray(urls);
        return urls;
     }
     
     // LoaderRepository overrides ------------------------------------
     
     public Class loadClass(String className) throws ClassNotFoundException
     {
        // if someone comes to us directly through LoaderRepository interface
        // notice that UCL loaders will skip this and invoke
        // loadClass(name, resolve, cl) directly
        return loadClass(className, false, 
Thread.currentThread().getContextClassLoader());
     }
     
     public Class loadClassWithout(ClassLoader loader, String className) throws 
ClassNotFoundException
     {
        throw new Error("NYI");
     }
  
     public void addClassLoader(ClassLoader loader)
     {
        // if you come to us as UCL we send you straight to the orbit
        if (loader instanceof UnifiedClassLoader)
           addUnifiedClassLoader((UnifiedClassLoader)loader);
        
        // if you come to us as URLCL we'll slice you up and
        // orbit UCL per URL
        else if (loader instanceof URLClassLoader)
        {
           URLClassLoader ucl = (URLClassLoader)loader;
           URL[] urls = ucl.getURLs();
           
           for (int i = 0; i < urls.length; ++i)
           {
              addUnifiedClassLoader(new UnifiedClassLoader(urls[i], this));
           }
        }
  
        else
  //         addNonDelegatingClassLoader(loader);
           throw new RuntimeException("ULR only allows UCL to be added");
     }
     
     private synchronized void addUnifiedClassLoader(UnifiedClassLoader cl)
     {
        cl.setRepository(this);
        
        // we should only keep the first classloader declared
        if (!classLoaders.contains(cl))
        {
           // We create a new copy of the classLoaders set.
           classLoaders = new HashSet(classLoaders);
           
           classLoaders.add(cl);
  
           // FIXME: log it         
           System.out.println("Libraries adding UnifiedClassLoader " + cl.hashCode() + 
" key URL " + cl.getURL());
        }
        else 
        {
           // FIXME: log it
           System.out.println("Libraries skipping duplicate UnifiedClassLoader for key 
URL " + cl.getURL());
        }
     }
  
     public synchronized void removeClassLoader(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))
        {
           // 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);
           }
        }
        
        // 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);
           }
        }
     }
     
  }
        
  
  
  
  
  
  

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

Reply via email to