[prev in list] [next in list] [prev in thread] [next in thread]
List: jboss-cvs-commits
Subject: [jboss-cvs] jmx/src/main/org/jboss/mx/loading UnifiedLoaderRepository2.java
From: Adrian Brock <ejort () users ! sourceforge ! net>
Date: 2002-08-31 23:02:13
[Download RAW message or body]
User: ejort
Date: 02/08/31 16:02:13
Modified: src/main/org/jboss/mx/loading Tag: Branch_3_0
UnifiedLoaderRepository2.java
Log:
Global resource caching
Revision Changes Path
No revision
No revision
1.1.2.6 +752 -702 \
jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepository2.java
Index: UnifiedLoaderRepository2.java
===================================================================
RCS file: /cvsroot/jboss/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepository2.java,v
retrieving revision 1.1.2.5
retrieving revision 1.1.2.6
diff -u -r1.1.2.5 -r1.1.2.6
--- UnifiedLoaderRepository2.java 21 Aug 2002 22:48:23 -0000 1.1.2.5
+++ UnifiedLoaderRepository2.java 31 Aug 2002 23:02:13 -0000 1.1.2.6
@@ -1,702 +1,752 @@
-/*
- * 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.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanNotificationInfo;
-import javax.management.Notification;
-import javax.management.NotificationBroadcaster;
-import javax.management.NotificationBroadcasterSupport;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-
-import org.jboss.mx.logging.Logger;
-
-/**
- * <description>
- *
- * @see <related>
- *
- * @author <a href="mailto:marc@jboss.org">Marc Fleury</a>
- * @author <a href="mailto:osh@sparre.dk">Ole Husgaard</a>
- * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
- * @author <a href="mailto:simone.bordet@hp.com">Simone Bordet</a>.
- * @version $Revision: 1.1.2.5 $
- * just a hint... xdoclet not really used
- * @jmx.name="JMImplementation:service=UnifiedLoaderRepository,name=Default"
- *
- */
-public class UnifiedLoaderRepository2 extends LoaderRepository
- implements NotificationBroadcaster, UnifiedLoaderRepository2MBean
-{
- // Static --------------------------------------------------------
- private static final Logger log = \
Logger.getLogger(UnifiedLoaderRepository2.class);
-
- // Attributes ----------------------------------------------------
-
- /**
- * The classloaders we use for loading classes.
- */
- private HashSet classLoaders = new HashSet();
-
- /** A set used to check for duplicate URLs. Previously this was handled
- by the UCL.equals, but this caused problems with Class.forName(String,
- boolean, ClassLoader) caching.
- */
- private HashSet classLoaderURLs = new HashSet();
-
- /**
- * The classes loaded, maps names to class objects.
- */
- private HashMap classes = new HashMap();
-
- /**
- * Maps class loaders to the set of classes they loaded.
- */
- private HashMap loaderToClassesMap = new HashMap();
-
- /**
- * Maps class loaders to the set of resource names they looked up.
- */
- private HashMap loaderToResourcesMap = new HashMap();
-
- /** A map of package names to the set of ClassLoaders which
- have classes in the package.
- */
- private HashMap packagesMap = new HashMap();
-
- /** A map of class loaders to the array of pckages names they serve
- */
- private HashMap loaderToPackagesMap = new HashMap();
-
- /**
- * The sequenceNumber used to number notifications.
- */
- private long sequenceNumber = 0;
-
- /**
- * We delegate our notification sending to a support object.
- */
- private final NotificationBroadcasterSupport broadcaster = new \
NotificationBroadcasterSupport();
-
- /**
- * The NotificationInfo we emit.
- */
- private MBeanNotificationInfo[] info;
-
-
- // Public --------------------------------------------------------
-
- public UnifiedClassLoader newClassLoader(final URL url, boolean \
addToRepository)
- throws Exception
- {
- UnifiedClassLoader2 ucl = new UnifiedClassLoader2(url, null, this);
- if( addToRepository )
- {
- UnifiedClassLoader delegate = ucl.getDelegate();
- this.addClassLoader(delegate);
- }
- return ucl;
- }
- public UnifiedClassLoader newClassLoader(final URL url, final URL origURL, \
boolean addToRepository)
- throws Exception
- {
- UnifiedClassLoader2 ucl = new UnifiedClassLoader2(url, origURL, this);
- if( addToRepository )
- {
- UnifiedClassLoader delegate = ucl.getDelegate();
- this.addClassLoader(delegate);
- }
- return ucl;
- }
-
- /**
- * Loads a class following the Unified ClassLoader architecture.
- */
- public Class loadClass(String name, boolean resolve, ClassLoader cl)
- throws ClassNotFoundException
- {
- // Try the cache before anything else.
- Class cls = loadClassFromCache(name, cl);
-
- // Found in cache, we're done
- if (cls != null) {return cls;}
-
- // Not found in cache, ask the calling classloader
- cls = loadClassFromClassLoader(name, resolve, cl);
-
- // The calling classloader sees the class, we're done
- if (cls != null) {return cls;}
-
- // Not visible by the calling classloader, iterate on the other classloaders
- cls = loadClassFromRepository(name, resolve, cl);
- if( cls == null && name.charAt(0) == '[' )
- {
- // First try to load the element class
- String subname = name.substring(2, name.length()-1);
- cls = loadClassFromRepository(subname, resolve, cl);
- if( cls != null )
- {
- // Retry loading the array class since we have the element class
- cls = loadClassFromRepository(name, resolve, cl);
- }
- }
-
- // Some other classloader sees the class, we're done
- if (cls != null) {return cls;}
-
- // This class is not visible
- throw new ClassNotFoundException(name);
- }
-
- /** Parse a class name into its package prefix. This has to handle
- array classes whose name is prefixed with [L.
- */
- private String getPackageName(String className)
- {
- int startIndex = 0;
- // Strip any leading "[+L" found in array class names
- if( className.charAt(0) == '[' )
- {
- // Move beyond the [...[L prefix
- startIndex = className.indexOf('L') + 1;
- }
- int endIndex = className.lastIndexOf('.');
- // Now extract the package name
- String pkgName = className;
- if( endIndex > 0 )
- pkgName = className.substring(startIndex, endIndex);
- return pkgName;
- }
-
- private String getResourcePackageName(String rsrcName)
- {
- int index = rsrcName.lastIndexOf('/');
- String pkgName = rsrcName;
- if( index > 0 )
- pkgName = rsrcName.substring(0, index);
- return pkgName.replace('/', '.');
- }
- /** Is the class in a package for which we have a class loader mapping
- */
- private boolean containsClassPackage(String className)
- {
- return packagesMap.containsKey(getPackageName(className));
- }
-
- private Class loadClassFromCache(String name, ClassLoader cl)
- {
- // Return classes from the global cache
- // In this case the classloader is not used.
- Class cls = (Class)classes.get(name);
- return cls;
- }
-
- private void cacheLoadedClass(String name, Class cls, ClassLoader cl)
- {
- // Update the global cache
- classes.put(name, cls);
-
- // Update the cache for this classloader
- // This is used to cycling classloaders
- HashSet classes = (HashSet)loaderToClassesMap.get(cl);
- if (classes == null)
- {
- classes = new HashSet();
- loaderToClassesMap.put(cl, classes);
- }
- classes.add(name);
- }
-
- private Class loadClassFromClassLoader(String name, boolean resolve, \
ClassLoader cl)
- {
- if (cl instanceof UnifiedClassLoader)
- {
- try
- {
- Class cls = ((UnifiedClassLoader)cl).loadClassLocally(name, resolve);
- cacheLoadedClass(name, cls, cl);
- return cls;
- }
- catch (ClassNotFoundException x)
- {
- // The class is not visible by the calling classloader
- }
- }
- return null;
- }
-
- private Class loadClassFromRepository(String name, boolean resolve, ClassLoader \
cl)
- {
- // Get the set of class loaders from the packages map
- String pkgName = getPackageName(name);
- HashSet pkgSet = (HashSet) this.packagesMap.get(pkgName);
- // If no pkg match was found there is no point looking any further
- if( pkgSet == null )
- return null;
-
- //for (Iterator i = classLoaders.iterator(); i.hasNext();)
- for(Iterator i = pkgSet.iterator(); i.hasNext();)
- {
- ClassLoader classloader = (ClassLoader)i.next();
- if (classloader.equals(cl))
- {
- continue;
- }
-
- if (classloader instanceof UnifiedClassLoader)
- {
- try
- {
- UnifiedClassLoader ucl = (UnifiedClassLoader) classloader;
- Class cls = ucl.loadClassLocally(name, resolve);
- cacheLoadedClass(name, cls, classloader);
- return cls;
- }
- catch (ClassNotFoundException ignored)
- {
- // Go on with next classloader
- }
- }
- }
- return null;
- }
-
- /**
- * Loads a resource following the Unified ClassLoader architecture
- */
- public URL getResource(String name, ClassLoader cl)
- {
- // getResource() calls are not synchronized on the classloader from JDK \
code.
- // First ask the cache (of the calling classloader)
- URL resource = getResourceFromCache(name, cl);
-
- // The resource was already loaded by the calling classloader, we're done
- if (resource != null) {return resource;}
-
- // Not found in cache, ask the calling classloader
- resource = getResourceFromClassLoader(name, cl);
-
- // The calling classloader sees the resource, we're done
- if (resource != null) {return resource;}
-
- // Not visible by the calling classloader, iterate on the other classloaders
- resource = getResourceFromRepository(name, cl);
-
- // Some other classloader sees the resource, we're done
- if (resource != null) {return resource;}
-
- // This resource is not visible
- return null;
- }
-
- private URL getResourceFromCache(String name, ClassLoader cl)
- {
- // Differently from classes, resource are not looked up in a global cache,
- // as it is possible that 2 classloaders have the same resource name \
(ejb-jar.xml),
- // a global cache will overwrite. Instead we look in the classloader's cache
- // that we mantain to cycle the classloaders
-
- if (loaderToResourcesMap.containsKey(cl))
- {
- HashMap resources = (HashMap)loaderToResourcesMap.get(cl);
- return (URL)resources.get(name);
- }
- return null;
- }
-
- private URL getResourceFromClassLoader(String name, ClassLoader cl)
- {
- if (cl instanceof UnifiedClassLoader)
- {
- URL url = ((UnifiedClassLoader)cl).getResourceLocally(name);
- cacheLoadedResource(name, url, cl);
- return url;
- }
- return null;
- }
-
- private URL getResourceFromRepository(String name, ClassLoader cl)
- {
- // Get the set of class loaders from the packages map
- String pkgName = getResourcePackageName(name);
- HashSet pkgSet = (HashSet) this.packagesMap.get(pkgName);
- Iterator i;
- if( pkgSet != null )
- i = pkgSet.iterator();
- // If no pkg match was found just go through all class loaders
- else
- i = classLoaders.iterator();
-
- while( i.hasNext() == true )
- {
- ClassLoader classloader = (ClassLoader)i.next();
- if (classloader.equals(cl))
- {
- continue;
- }
-
- if (classloader instanceof UnifiedClassLoader)
- {
- URL url = ((UnifiedClassLoader)classloader).getResourceLocally(name);
- if (url != null)
- {
- cacheLoadedResource(name, url, classloader);
- return url;
- }
- else
- {
- // Do nothing, go on with next classloader
- }
- }
- }
- return null;
- }
-
- private void cacheLoadedResource(String name, URL url, ClassLoader cl)
- {
- // Differently from classes there is no global cache.
-
- // Update the cache for this classloader only
- // This is used for cycling classloaders
- HashMap resources = (HashMap)loaderToResourcesMap.get(cl);
- if (resources == null)
- {
- resources = new HashMap();
- loaderToResourcesMap.put(cl, resources);
- }
- resources.put(name, url);
- }
-
- /**
- * Obtain a listing of the URL for all UnifiedClassLoaders associated with
- * the ServiceLibraries
- */
- public URL[] getURLs()
- {
- HashSet classpath = new HashSet();
-
- // I have to synchronize as I will iterate on the classloaders
- // This avoid someone else calls add/removeClassLoader while I iterate here
- synchronized (this)
- {
- for (Iterator iter = classLoaders.iterator(); iter.hasNext();)
- {
- Object obj = iter.next();
- if (obj instanceof UnifiedClassLoader)
- {
- UnifiedClassLoader cl = (UnifiedClassLoader)obj;
- 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
- }
-
- return (URL[])classpath.toArray(new URL[classpath.size()]);
- }
-
- // 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
- ClassLoader scl = Thread.currentThread().getContextClassLoader();
- Class clazz = null;
- synchronized( UnifiedLoaderRepository2.class )
- {
- try
- {
- clazz = loadClass(className, false, scl);
- }
- catch (ClassNotFoundException e)
- {
- // If the TCL is not a UnifiedClassLoader then the scl was not asked
- // if it could load the class. Do so here.
- if ((scl instanceof UnifiedClassLoader) == false)
- clazz = scl.loadClass(className);
- // Else we need to rethrow the CNFE
- else
- throw e;
- }
- }
- return clazz;
- }
-
- public Class loadClassWithout(ClassLoader loader, String className)
- throws ClassNotFoundException
- {
- throw new ClassNotFoundException("NYI");
- }
-
- public void addClassLoader(ClassLoader loader)
- {
- synchronized( UnifiedLoaderRepository2.class )
- {
- // 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");
- log.warn("Tried to add non- URLClassLoader. Ignored");
- } // end of else
- }
- }
-
- private void addUnifiedClassLoader(UnifiedClassLoader cl)
- {
- cl.setRepository(this);
- // See if this URL already exists
- URL url = cl.getURL();
- boolean added = false;
- boolean exists = classLoaderURLs.contains(url);
- // If already present will not be added
- if(!exists)
- {
- added = classLoaders.add(cl);
- classLoaderURLs.add(url);
- }
- if (added)
- {
- log.debug("Adding "+cl);
- updatePackageMap(cl);
- }
- else
- {
- log.debug("Skipping duplicate "+cl);
- }
- }
-
- /** Walk through the class loader URL to see what packages it is capable
- of handling
- */
- private void updatePackageMap(UnifiedClassLoader cl)
- {
- try
- {
- String[] pkgNames = ClassLoaderUtils.updatePackageMap(cl, packagesMap);
- loaderToPackagesMap.put(cl, pkgNames);
- }
- catch(Exception e)
- {
- if( log.isTraceEnabled() )
- log.trace("Failed to update pkgs for cl="+cl, e);
- else
- log.debug("Failed to update pkgs for cl="+cl, e);
- }
- }
-
- public void removeClassLoader(ClassLoader cl)
- {
- synchronized( UnifiedLoaderRepository2.class )
- {
- if( cl instanceof UnifiedClassLoader )
- {
- UnifiedClassLoader ucl = (UnifiedClassLoader) cl;
- URL url = ucl.getURL();
- classLoaderURLs.remove(url);
- }
- boolean removed = classLoaders.remove(cl);
- log.debug("UnifiedLoaderRepository removed("+removed+") " + cl);
-
- // Take care also of the cycling mapping for classes
- if (loaderToClassesMap.containsKey(cl))
- {
- HashSet loaded = (HashSet)loaderToClassesMap.remove(cl);
- // This classloader has loaded at least one class
- if (loaded != null)
- {
- // Notify that classes are about to be removed
- for (Iterator iter = loaded.iterator(); iter.hasNext();)
- {
- broadcaster.sendNotification(new Notification(CLASS_REMOVED, this, \
getNextSequenceNumber(), (String)iter.next()));
- }
-
- // Remove the classes from the global cache
- for (Iterator i = loaded.iterator(); i.hasNext();)
- {
- String cls = (String)i.next();
- this.classes.remove(cls);
- }
- }
- }
-
- // Take care also of the cycling mapping for resources
- // There is no global cache for resources
- if (loaderToResourcesMap.containsKey(cl))
- {
- HashMap resources = (HashMap)loaderToResourcesMap.remove(cl);
- }
-
- // Clean up the package name to class loader mapping
- String[] pkgNames = (String[]) loaderToPackagesMap.get(cl);
- int length = pkgNames != null ? pkgNames.length : 0;
- for(int p = 0; p < length; p ++)
- {
- String pkgName = pkgNames[p];
- HashSet pkgSet = (HashSet) packagesMap.get(pkgName);
- if( pkgSet != null )
- {
- pkgSet.remove(cl);
- if( pkgSet.isEmpty() )
- packagesMap.remove(pkgName);
- }
- }
- }
- }
-
- /**
- * This method provides an mbean-accessible way to add a
- * UnifiedClassloader, and sends a notification when it is added.
- *
- * @param ucl an <code>UnifiedClassLoader</code> value
- * @return a <code>LoaderRepository</code> value
- *
- * @jmx.managed-operation
- */
- public LoaderRepository registerClassLoader(UnifiedClassLoader ucl)
- {
- addClassLoader(ucl);
- Notification msg = new Notification(CLASSLOADER_ADDED, this, \
getNextSequenceNumber());
- msg.setUserData(ucl);
- broadcaster.sendNotification(msg);
-
- return this;
- }
-
- /**
- * @jmx.managed-operation
- */
- public LoaderRepository getInstance()
- {
- return this;
- }
-
- // implementation of javax.management.NotificationBroadcaster interface
-
- /**
- * addNotificationListener delegates to the broadcaster object we hold.
- *
- * @param listener a <code>NotificationListener</code> value
- * @param filter a <code>NotificationFilter</code> value
- * @param handback an <code>Object</code> value
- * @exception IllegalArgumentException if an error occurs
- */
- public void addNotificationListener(NotificationListener listener, \
NotificationFilter filter, Object handback) throws \
IllegalArgumentException
- {
- broadcaster.addNotificationListener(listener, filter, handback);
- }
-
- /**
- *
- * @return <description>
- */
- public MBeanNotificationInfo[] getNotificationInfo()
- {
- if (info == null)
- {
- info = new MBeanNotificationInfo[]{
- new MBeanNotificationInfo(new String[]{"CLASSLOADER_ADDED"},
- "javax.management.Notification",
- "Notification that a classloader has been \
added to the extensible classloader"),
- new MBeanNotificationInfo(new String[]{"CLASS_REMOVED"},
- "javax.management.Notification",
- "Notification that a class has been removed \
from the extensible classloader")
-
- };
- }
- return info;
- }
-
- /**
- * removeNotificationListener delegates to our broadcaster object
- *
- * @param listener a <code>NotificationListener</code> value
- * @exception ListenerNotFoundException if an error occurs
- */
- public void removeNotificationListener(NotificationListener listener) throws \
ListenerNotFoundException
- {
- broadcaster.removeNotificationListener(listener);
- }
-
- /**
- * Iterates through the current class loaders and tries to find the
- * given class name.
- * @return the Class object for name if found, null otherwise.
- *
- * @jmx.managed-operation
- */
- public Class findClass(String name)
- {
- // 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";
-
- // I have to synchronize as I will iterate on the classloaders
- // This avoid someone else calls add/removeClassLoader while I iterate here
- synchronized (this)
- {
- for (Iterator iter = classLoaders.iterator(); iter.hasNext();)
- {
- ClassLoader cl = (ClassLoader)iter.next();
- URL classURL = cl.getResource(classRsrcName);
- log.trace("Checking CL for URL: "+classURL);
- if (classURL != null)
- {
- try
- {
- // Since the class was found we can load it which should be a \
noop
- Class cls = cl.loadClass(name);
- log.trace("Found class in: "+cls.getProtectionDomain());
- return cls;
- }
- catch (ClassNotFoundException e)
- {
- log.debug("Failed to load class: " + name, e);
- }
- }
- }
- }
- log.trace("Class not found");
- return null;
- }
-
- private synchronized long getNextSequenceNumber()
- {
- return sequenceNumber++;
- }
-
-}
+/*
+ * 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.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+
+import org.jboss.mx.logging.Logger;
+
+/**
+ * <description>
+ *
+ * @see <related>
+ *
+ * @author <a href="mailto:marc@jboss.org">Marc Fleury</a>
+ * @author <a href="mailto:osh@sparre.dk">Ole Husgaard</a>
+ * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
+ * @author <a href="mailto:simone.bordet@hp.com">Simone Bordet</a>.
+ * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
+ * @version $Revision: 1.1.2.6 $
+ * just a hint... xdoclet not really used
+ * @jmx.name="JMImplementation:service=UnifiedLoaderRepository,name=Default"
+ *
+ */
+public class UnifiedLoaderRepository2 extends LoaderRepository
+ implements NotificationBroadcaster, UnifiedLoaderRepository2MBean
+{
+ // Static --------------------------------------------------------
+ private static final Logger log = \
Logger.getLogger(UnifiedLoaderRepository2.class); +
+ // Attributes ----------------------------------------------------
+
+ /**
+ * The classloaders we use for loading classes.
+ */
+ private HashSet classLoaders = new HashSet();
+
+ /** A set used to check for duplicate URLs. Previously this was handled
+ by the UCL.equals, but this caused problems with Class.forName(String,
+ boolean, ClassLoader) caching.
+ */
+ private HashSet classLoaderURLs = new HashSet();
+
+ /**
+ * The classes loaded, maps names to class objects.
+ */
+ private HashMap classes = new HashMap();
+
+ /**
+ * Maps class loaders to the set of classes they loaded.
+ */
+ private HashMap loaderToClassesMap = new HashMap();
+
+ /**
+ * Maps class loaders to the set of resource names they looked up.
+ */
+ private HashMap loaderToResourcesMap = new HashMap();
+
+ /**
+ * The global resources. Map of name to ResourceInfo
+ */
+ private HashMap globalResources = new HashMap();
+
+ /** A map of package names to the set of ClassLoaders which
+ have classes in the package.
+ */
+ private HashMap packagesMap = new HashMap();
+
+ /** A map of class loaders to the array of pckages names they serve
+ */
+ private HashMap loaderToPackagesMap = new HashMap();
+
+ /**
+ * The sequenceNumber used to number notifications.
+ */
+ private long sequenceNumber = 0;
+
+ /**
+ * We delegate our notification sending to a support object.
+ */
+ private final NotificationBroadcasterSupport broadcaster = new \
NotificationBroadcasterSupport(); +
+ /**
+ * The NotificationInfo we emit.
+ */
+ private MBeanNotificationInfo[] info;
+
+
+ // Public --------------------------------------------------------
+
+ public UnifiedClassLoader newClassLoader(final URL url, boolean \
addToRepository) + throws Exception
+ {
+ UnifiedClassLoader2 ucl = new UnifiedClassLoader2(url, null, this);
+ if( addToRepository )
+ {
+ UnifiedClassLoader delegate = ucl.getDelegate();
+ this.addClassLoader(delegate);
+ }
+ return ucl;
+ }
+ public UnifiedClassLoader newClassLoader(final URL url, final URL origURL, \
boolean addToRepository) + throws Exception
+ {
+ UnifiedClassLoader2 ucl = new UnifiedClassLoader2(url, origURL, this);
+ if( addToRepository )
+ {
+ UnifiedClassLoader delegate = ucl.getDelegate();
+ this.addClassLoader(delegate);
+ }
+ return ucl;
+ }
+
+ /**
+ * Loads a class following the Unified ClassLoader architecture.
+ */
+ public Class loadClass(String name, boolean resolve, ClassLoader cl)
+ throws ClassNotFoundException
+ {
+ // Try the cache before anything else.
+ Class cls = loadClassFromCache(name, cl);
+
+ // Found in cache, we're done
+ if (cls != null) {return cls;}
+
+ // Not found in cache, ask the calling classloader
+ cls = loadClassFromClassLoader(name, resolve, cl);
+
+ // The calling classloader sees the class, we're done
+ if (cls != null) {return cls;}
+
+ // Not visible by the calling classloader, iterate on the other classloaders
+ cls = loadClassFromRepository(name, resolve, cl);
+ if( cls == null && name.charAt(0) == '[' )
+ {
+ // First try to load the element class
+ String subname = name.substring(2, name.length()-1);
+ cls = loadClassFromRepository(subname, resolve, cl);
+ if( cls != null )
+ {
+ // Retry loading the array class since we have the element class
+ cls = loadClassFromRepository(name, resolve, cl);
+ }
+ }
+
+ // Some other classloader sees the class, we're done
+ if (cls != null) {return cls;}
+
+ // This class is not visible
+ throw new ClassNotFoundException(name);
+ }
+
+ /** Parse a class name into its package prefix. This has to handle
+ array classes whose name is prefixed with [L.
+ */
+ private String getPackageName(String className)
+ {
+ int startIndex = 0;
+ // Strip any leading "[+L" found in array class names
+ if( className.charAt(0) == '[' )
+ {
+ // Move beyond the [...[L prefix
+ startIndex = className.indexOf('L') + 1;
+ }
+ int endIndex = className.lastIndexOf('.');
+ // Now extract the package name
+ String pkgName = className;
+ if( endIndex > 0 )
+ pkgName = className.substring(startIndex, endIndex);
+ return pkgName;
+ }
+
+ private String getResourcePackageName(String rsrcName)
+ {
+ int index = rsrcName.lastIndexOf('/');
+ String pkgName = rsrcName;
+ if( index > 0 )
+ pkgName = rsrcName.substring(0, index);
+ return pkgName.replace('/', '.');
+ }
+ /** Is the class in a package for which we have a class loader mapping
+ */
+ private boolean containsClassPackage(String className)
+ {
+ return packagesMap.containsKey(getPackageName(className));
+ }
+
+ private Class loadClassFromCache(String name, ClassLoader cl)
+ {
+ // Return classes from the global cache
+ // In this case the classloader is not used.
+ Class cls = (Class)classes.get(name);
+ return cls;
+ }
+
+ private void cacheLoadedClass(String name, Class cls, ClassLoader cl)
+ {
+ // Update the global cache
+ classes.put(name, cls);
+
+ // Update the cache for this classloader
+ // This is used to cycling classloaders
+ HashSet classes = (HashSet)loaderToClassesMap.get(cl);
+ if (classes == null)
+ {
+ classes = new HashSet();
+ loaderToClassesMap.put(cl, classes);
+ }
+ classes.add(name);
+ }
+
+ private Class loadClassFromClassLoader(String name, boolean resolve, \
ClassLoader cl) + {
+ if (cl instanceof UnifiedClassLoader)
+ {
+ try
+ {
+ Class cls = ((UnifiedClassLoader)cl).loadClassLocally(name, resolve);
+ cacheLoadedClass(name, cls, cl);
+ return cls;
+ }
+ catch (ClassNotFoundException x)
+ {
+ // The class is not visible by the calling classloader
+ }
+ }
+ return null;
+ }
+
+ private Class loadClassFromRepository(String name, boolean resolve, ClassLoader \
cl) + {
+ // Get the set of class loaders from the packages map
+ String pkgName = getPackageName(name);
+ HashSet pkgSet = (HashSet) this.packagesMap.get(pkgName);
+ // If no pkg match was found there is no point looking any further
+ if( pkgSet == null )
+ return null;
+
+ //for (Iterator i = classLoaders.iterator(); i.hasNext();)
+ for(Iterator i = pkgSet.iterator(); i.hasNext();)
+ {
+ ClassLoader classloader = (ClassLoader)i.next();
+ if (classloader.equals(cl))
+ {
+ continue;
+ }
+
+ if (classloader instanceof UnifiedClassLoader)
+ {
+ try
+ {
+ UnifiedClassLoader ucl = (UnifiedClassLoader) classloader;
+ Class cls = ucl.loadClassLocally(name, resolve);
+ cacheLoadedClass(name, cls, classloader);
+ return cls;
+ }
+ catch (ClassNotFoundException ignored)
+ {
+ // Go on with next classloader
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Loads a resource following the Unified ClassLoader architecture
+ */
+ public URL getResource(String name, ClassLoader cl)
+ {
+ // getResource() calls are not synchronized on the classloader from JDK \
code. + // First ask the cache (of the calling classloader)
+ URL resource = getResourceFromCache(name, cl);
+
+ // The resource was already loaded by the calling classloader, we're done
+ if (resource != null) {return resource;}
+
+ // Not found in cache, ask the calling classloader
+ resource = getResourceFromClassLoader(name, cl);
+
+ // The calling classloader sees the resource, we're done
+ if (resource != null) {return resource;}
+
+ // Not found in classloader, ask the global cache
+ resource = getResourceFromGlobalCache(name);
+
+ // The cache has it, we are done
+ if (resource != null) {return resource;}
+
+ // Not visible in global cache, iterate on all classloaders
+ resource = getResourceFromRepository(name, cl);
+
+ // Some other classloader sees the resource, we're done
+ if (resource != null) {return resource;}
+
+ // This resource is not visible
+ return null;
+ }
+
+ private URL getResourceFromCache(String name, ClassLoader cl)
+ {
+ // Differently from classes, resource are not looked up in a global cache,
+ // as it is possible that 2 classloaders have the same resource name \
(ejb-jar.xml), + // a global cache will overwrite. Instead we look in the \
classloader's cache + // that we mantain to cycle the classloaders
+
+ if (loaderToResourcesMap.containsKey(cl))
+ {
+ HashMap resources = (HashMap)loaderToResourcesMap.get(cl);
+ return (URL)resources.get(name);
+ }
+ return null;
+ }
+
+ private URL getResourceFromClassLoader(String name, ClassLoader cl)
+ {
+ if (cl instanceof UnifiedClassLoader)
+ {
+ URL url = ((UnifiedClassLoader)cl).getResourceLocally(name);
+ cacheLoadedResource(name, url, cl);
+ return url;
+ }
+ return null;
+ }
+
+ private URL getResourceFromGlobalCache(String name)
+ {
+ // Invoked after the classloader is asked, caches the
+ // results of global lookups
+ ResourceInfo ri = (ResourceInfo) globalResources.get(name);
+ if (ri != null)
+ return ri.url;
+ return null;
+ }
+
+ private URL getResourceFromRepository(String name, ClassLoader cl)
+ {
+ // Get the set of class loaders from the packages map
+ String pkgName = getResourcePackageName(name);
+ HashSet pkgSet = (HashSet) this.packagesMap.get(pkgName);
+ Iterator i;
+ if( pkgSet != null )
+ i = pkgSet.iterator();
+ // If no pkg match was found just go through all class loaders
+ else
+ i = classLoaders.iterator();
+
+ while( i.hasNext() == true )
+ {
+ ClassLoader classloader = (ClassLoader)i.next();
+ if (classloader.equals(cl))
+ {
+ continue;
+ }
+
+ if (classloader instanceof UnifiedClassLoader)
+ {
+ URL url = ((UnifiedClassLoader)classloader).getResourceLocally(name);
+ if (url != null)
+ {
+ cacheLoadedResource(name, url, classloader);
+ cacheGlobalResource(name, url, classloader);
+ return url;
+ }
+ else
+ {
+ // Do nothing, go on with next classloader
+ }
+ }
+ }
+ return null;
+ }
+
+ private void cacheLoadedResource(String name, URL url, ClassLoader cl)
+ {
+ // Differently from classes there is no global cache.
+
+ // Update the cache for this classloader only
+ // This is used for cycling classloaders
+ HashMap resources = (HashMap)loaderToResourcesMap.get(cl);
+ if (resources == null)
+ {
+ resources = new HashMap();
+ loaderToResourcesMap.put(cl, resources);
+ }
+ resources.put(name, url);
+ }
+
+ private void cacheGlobalResource(String name, URL url, ClassLoader cl)
+ {
+ // Resources looked up from one classloader, found in another.
+ globalResources.put(name, new ResourceInfo(url, cl));
+ }
+
+ /**
+ * Obtain a listing of the URL for all UnifiedClassLoaders associated with
+ * the ServiceLibraries
+ */
+ public URL[] getURLs()
+ {
+ HashSet classpath = new HashSet();
+
+ // I have to synchronize as I will iterate on the classloaders
+ // This avoid someone else calls add/removeClassLoader while I iterate here
+ synchronized (this)
+ {
+ for (Iterator iter = classLoaders.iterator(); iter.hasNext();)
+ {
+ Object obj = iter.next();
+ if (obj instanceof UnifiedClassLoader)
+ {
+ UnifiedClassLoader cl = (UnifiedClassLoader)obj;
+ 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
+ }
+
+ return (URL[])classpath.toArray(new URL[classpath.size()]);
+ }
+
+ // 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
+ ClassLoader scl = Thread.currentThread().getContextClassLoader();
+ Class clazz = null;
+ synchronized( UnifiedLoaderRepository2.class )
+ {
+ try
+ {
+ clazz = loadClass(className, false, scl);
+ }
+ catch (ClassNotFoundException e)
+ {
+ // If the TCL is not a UnifiedClassLoader then the scl was not asked
+ // if it could load the class. Do so here.
+ if ((scl instanceof UnifiedClassLoader) == false)
+ clazz = scl.loadClass(className);
+ // Else we need to rethrow the CNFE
+ else
+ throw e;
+ }
+ }
+ return clazz;
+ }
+
+ public Class loadClassWithout(ClassLoader loader, String className)
+ throws ClassNotFoundException
+ {
+ throw new ClassNotFoundException("NYI");
+ }
+
+ public void addClassLoader(ClassLoader loader)
+ {
+ synchronized( UnifiedLoaderRepository2.class )
+ {
+ // 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");
+ log.warn("Tried to add non- URLClassLoader. Ignored");
+ } // end of else
+ }
+ }
+
+ private void addUnifiedClassLoader(UnifiedClassLoader cl)
+ {
+ cl.setRepository(this);
+ // See if this URL already exists
+ URL url = cl.getURL();
+ boolean added = false;
+ boolean exists = classLoaderURLs.contains(url);
+ // If already present will not be added
+ if(!exists)
+ {
+ added = classLoaders.add(cl);
+ classLoaderURLs.add(url);
+ }
+ if (added)
+ {
+ log.debug("Adding "+cl);
+ updatePackageMap(cl);
+ }
+ else
+ {
+ log.debug("Skipping duplicate "+cl);
+ }
+ }
+
+ /** Walk through the class loader URL to see what packages it is capable
+ of handling
+ */
+ private void updatePackageMap(UnifiedClassLoader cl)
+ {
+ try
+ {
+ String[] pkgNames = ClassLoaderUtils.updatePackageMap(cl, packagesMap);
+ loaderToPackagesMap.put(cl, pkgNames);
+ }
+ catch(Exception e)
+ {
+ if( log.isTraceEnabled() )
+ log.trace("Failed to update pkgs for cl="+cl, e);
+ else
+ log.debug("Failed to update pkgs for cl="+cl, e);
+ }
+ }
+
+ public void removeClassLoader(ClassLoader cl)
+ {
+ synchronized( UnifiedLoaderRepository2.class )
+ {
+ if( cl instanceof UnifiedClassLoader )
+ {
+ UnifiedClassLoader ucl = (UnifiedClassLoader) cl;
+ URL url = ucl.getURL();
+ classLoaderURLs.remove(url);
+ }
+ boolean removed = classLoaders.remove(cl);
+ log.debug("UnifiedLoaderRepository removed("+removed+") " + cl);
+
+ // Take care also of the cycling mapping for classes
+ if (loaderToClassesMap.containsKey(cl))
+ {
+ HashSet loaded = (HashSet)loaderToClassesMap.remove(cl);
+ // This classloader has loaded at least one class
+ if (loaded != null)
+ {
+ // Notify that classes are about to be removed
+ for (Iterator iter = loaded.iterator(); iter.hasNext();)
+ {
+ broadcaster.sendNotification(new Notification(CLASS_REMOVED, this, \
getNextSequenceNumber(), (String)iter.next())); + }
+
+ // Remove the classes from the global cache
+ for (Iterator i = loaded.iterator(); i.hasNext();)
+ {
+ String cls = (String)i.next();
+ this.classes.remove(cls);
+ }
+ }
+ }
+
+ // Take care also of the cycling mapping for resources
+ if (loaderToResourcesMap.containsKey(cl))
+ {
+ HashMap resources = (HashMap)loaderToResourcesMap.remove(cl);
+
+ // Remove the resources from the global cache that are from this \
classloader + if (resources != null)
+ {
+ for (Iterator i = resources.keySet().iterator(); i.hasNext();)
+ {
+ String name = (String) i.next();
+ ResourceInfo ri = (ResourceInfo) globalResources.get(name);
+ if (ri != null && ri.cl == cl)
+ globalResources.remove(name);
+ }
+ }
+ }
+
+ // Clean up the package name to class loader mapping
+ String[] pkgNames = (String[]) loaderToPackagesMap.get(cl);
+ int length = pkgNames != null ? pkgNames.length : 0;
+ for(int p = 0; p < length; p ++)
+ {
+ String pkgName = pkgNames[p];
+ HashSet pkgSet = (HashSet) packagesMap.get(pkgName);
+ if( pkgSet != null )
+ {
+ pkgSet.remove(cl);
+ if( pkgSet.isEmpty() )
+ packagesMap.remove(pkgName);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method provides an mbean-accessible way to add a
+ * UnifiedClassloader, and sends a notification when it is added.
+ *
+ * @param ucl an <code>UnifiedClassLoader</code> value
+ * @return a <code>LoaderRepository</code> value
+ *
+ * @jmx.managed-operation
+ */
+ public LoaderRepository registerClassLoader(UnifiedClassLoader ucl)
+ {
+ addClassLoader(ucl);
+ Notification msg = new Notification(CLASSLOADER_ADDED, this, \
getNextSequenceNumber()); + msg.setUserData(ucl);
+ broadcaster.sendNotification(msg);
+
+ return this;
+ }
+
+ /**
+ * @jmx.managed-operation
+ */
+ public LoaderRepository getInstance()
+ {
+ return this;
+ }
+
+ // implementation of javax.management.NotificationBroadcaster interface
+
+ /**
+ * addNotificationListener delegates to the broadcaster object we hold.
+ *
+ * @param listener a <code>NotificationListener</code> value
+ * @param filter a <code>NotificationFilter</code> value
+ * @param handback an <code>Object</code> value
+ * @exception IllegalArgumentException if an error occurs
+ */
+ public void addNotificationListener(NotificationListener listener, \
NotificationFilter filter, Object handback) throws IllegalArgumentException + {
+ broadcaster.addNotificationListener(listener, filter, handback);
+ }
+
+ /**
+ *
+ * @return <description>
+ */
+ public MBeanNotificationInfo[] getNotificationInfo()
+ {
+ if (info == null)
+ {
+ info = new MBeanNotificationInfo[]{
+ new MBeanNotificationInfo(new String[]{"CLASSLOADER_ADDED"},
+ "javax.management.Notification",
+ "Notification that a classloader has been \
added to the extensible classloader"), + new MBeanNotificationInfo(new \
String[]{"CLASS_REMOVED"}, + \
"javax.management.Notification", + \
"Notification that a class has been removed from the extensible classloader") +
+ };
+ }
+ return info;
+ }
+
+ /**
+ * removeNotificationListener delegates to our broadcaster object
+ *
+ * @param listener a <code>NotificationListener</code> value
+ * @exception ListenerNotFoundException if an error occurs
+ */
+ public void removeNotificationListener(NotificationListener listener) throws \
ListenerNotFoundException + {
+ broadcaster.removeNotificationListener(listener);
+ }
+
+ /**
+ * Iterates through the current class loaders and tries to find the
+ * given class name.
+ * @return the Class object for name if found, null otherwise.
+ *
+ * @jmx.managed-operation
+ */
+ public Class findClass(String name)
+ {
+ // 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";
+
+ // I have to synchronize as I will iterate on the classloaders
+ // This avoid someone else calls add/removeClassLoader while I iterate here
+ synchronized (this)
+ {
+ for (Iterator iter = classLoaders.iterator(); iter.hasNext();)
+ {
+ ClassLoader cl = (ClassLoader)iter.next();
+ URL classURL = cl.getResource(classRsrcName);
+ log.trace("Checking CL for URL: "+classURL);
+ if (classURL != null)
+ {
+ try
+ {
+ // Since the class was found we can load it which should be a \
noop + Class cls = cl.loadClass(name);
+ log.trace("Found class in: "+cls.getProtectionDomain());
+ return cls;
+ }
+ catch (ClassNotFoundException e)
+ {
+ log.debug("Failed to load class: " + name, e);
+ }
+ }
+ }
+ }
+ log.trace("Class not found");
+ return null;
+ }
+
+ private synchronized long getNextSequenceNumber()
+ {
+ return sequenceNumber++;
+ }
+
+ private static class ResourceInfo
+ {
+ public URL url;
+ public ClassLoader cl;
+ public ResourceInfo(URL url, ClassLoader cl)
+ {
+ this.url = url;
+ this.cl = cl;
+ }
+ }
+}
-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone? Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390
_______________________________________________
jboss-cvs-commits mailing list
jboss-cvs-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jboss-cvs-commits
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic