[Jboss-cvs] JBossAS SVN: r56381 - branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Aug 28 22:02:36 EDT 2006


Author: scott.stark at jboss.org
Date: 2006-08-28 22:02:32 -0400 (Mon, 28 Aug 2006)
New Revision: 56381

Added:
   branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/ClassLoadingTaskDCL.java
   branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/DomainClassLoaderUCLImpl.java
   branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/LoadMgrDCL.java
   branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCL.java
   branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCLMBean.java
Log:
Initial port of ucl/ulr to DomainClassLoader/ClassLoadingDomain

Copied: branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/ClassLoadingTaskDCL.java (from rev 56376, trunk/jmx/src/main/org/jboss/mx/loading/ClassLoadingTask.java)
===================================================================
--- trunk/jmx/src/main/org/jboss/mx/loading/ClassLoadingTask.java	2006-08-29 00:48:36 UTC (rev 56376)
+++ branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/ClassLoadingTaskDCL.java	2006-08-29 02:02:32 UTC (rev 56381)
@@ -0,0 +1,254 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.mx.loading;
+
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.util.Comparator;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+import org.jboss.logging.Logger;
+
+/** An encapsulation of a UCL3.loadClass task.
+ * @author Scott.Stark at jboss.org
+ * @version $Revision$
+*/
+public class ClassLoadingTaskDCL
+{
+   protected static Logger log = Logger.getLogger(ClassLoadingTaskDCL.class);
+   protected static Comparator taskComparator = new ThreadTaskComparator();
+
+   public static final int FOUND_CLASS_LOADER = 1;
+   public static final int NEXT_EVENT = 2;
+   public static final int WAIT_ON_EVENT = 3;
+   public static final int FINISHED = 4;
+
+   protected String classname;
+   protected Thread requestingThread;
+   protected LegacyDomainClassLoader requestingClassLoader;
+   protected Class loadedClass;
+   protected int loadOrder = Integer.MAX_VALUE;
+   protected int stopOrder = Integer.MAX_VALUE;
+   protected Throwable loadException;
+   /** The number of ThreadTasks remaining */
+   protected int threadTaskCount;
+   /** The state of the requestingThread */
+   protected int state;
+   /** The Logger trace level flag */
+   protected boolean trace;
+
+   protected int numCCE;
+
+   /** Compare ThreadTask first based on their order ivar, and then the
+    * relative ordering with which their UCLs were added to the ULR.
+    */
+   static class ThreadTaskComparator implements Comparator
+   {
+      public int compare(Object o1, Object o2)
+      {
+         ThreadTask t1 = (ThreadTask) o1;
+         ThreadTask t2 = (ThreadTask) o2;
+         int compare = t1.order - t2.order;
+         /*
+         if( compare == 0 )
+         {
+            compare = t1.ucl.getAddedOrder() - t2.ucl.getAddedOrder();
+         }
+         */
+         return compare;
+      }
+   }
+
+   /** An ecapsulation of a <Thread, UCL3> task used when requestingClassLoader
+    * needs to ask another UCL3 to perform the class loading.
+    */
+   class ThreadTask
+   {
+      /** The class loader for the classname package */
+      LegacyDomainClassLoader ucl;
+      /** The thread that owns the ucl monitor */
+      Thread t;
+      /** The relative order of the task. If o0 < o1 then the class loaded
+         by task o0 is preferred to o1.
+       */
+      int order;
+      boolean releaseInNextTask;
+
+      ThreadTask(LegacyDomainClassLoader ucl, Thread t, int order,
+         boolean releaseInNextTask)
+      {
+         this.ucl = ucl;
+         this.t = t;
+         this.order = order;
+         this.releaseInNextTask = releaseInNextTask;
+      }
+
+      public String toString()
+      {
+         return "{t="+t+", ucl="+ucl+", name="+classname
+            +", requestingThread="+requestingThread
+            +", order="+order+", releaseInNextTask="+releaseInNextTask
+            +"}";
+      }
+
+      String getClassname()
+      {
+         return classname;
+      }
+      Class getLoadedClass()
+      {
+         return loadedClass;
+      }
+      ClassLoadingTaskDCL getLoadTask()
+      {
+         return ClassLoadingTaskDCL.this;
+      }
+
+      void run() throws ClassNotFoundException
+      {
+         Class theClass = null;
+         try
+         {
+            if( loadedClass == null )
+            {
+               theClass = ucl.loadClassLocally(classname, false);
+               setLoadedClass(theClass, order);
+            }
+            else if( trace )
+            {
+               log.trace("Already found class("+loadedClass+"), skipping loadClassLocally");
+            }
+         }
+         finally
+         {
+            ;//setLoadedClass(theClass, order);
+         }
+      }
+   }
+
+   protected ClassLoadingTaskDCL(String classname, LegacyDomainClassLoader requestingClassLoader,
+         Thread requestingThread)
+   {
+      this(classname, requestingClassLoader, requestingThread, Integer.MAX_VALUE);
+   }
+   
+   protected ClassLoadingTaskDCL(String classname, LegacyDomainClassLoader requestingClassLoader,
+      Thread requestingThread, int stopAt)
+   {
+      this.requestingThread = requestingThread;
+      this.requestingClassLoader = requestingClassLoader;
+      this.classname = classname;
+      this.stopOrder = stopAt;
+      this.trace = log.isTraceEnabled();
+   }
+
+   public String toString()
+   {
+      StringBuffer buffer = new StringBuffer(super.toString());
+      buffer.append('{');
+      buffer.append("classname: "+classname);
+      buffer.append(", requestingThread: "+requestingThread);
+      buffer.append(", requestingClassLoader: "+requestingClassLoader);
+      buffer.append(", loadedClass: "+loadedClass);
+      ClassToStringAction.toString(loadedClass, buffer);
+      buffer.append(", loadOrder: "+loadOrder);
+      buffer.append(", loadException: "+loadException);
+      buffer.append(", threadTaskCount: "+threadTaskCount);
+      buffer.append(", state: "+state);
+      buffer.append(", #CCE: "+numCCE);
+      buffer.append('}');
+      if( trace && loadException != null )
+      {
+         StringWriter sw = new StringWriter();
+         PrintWriter pw = new PrintWriter(sw);
+         loadException.printStackTrace(pw);
+         buffer.append("loadException details:\n");
+         buffer.append(sw.toString());
+      }
+      return buffer.toString();
+   }
+
+   ThreadTask newThreadTask(LegacyDomainClassLoader ucl, Thread t, int order,
+      boolean reschedule, boolean releaseInNextTask)
+   {
+      // Only update the threadTaskCount if this is not a reschedule
+      if( reschedule == false )
+         threadTaskCount ++;
+      return new ThreadTask(ucl, t, order, releaseInNextTask);
+   }
+   
+   synchronized void setLoadError(Throwable t)
+   {
+       this.threadTaskCount--;
+        if( trace )
+            log.trace("setLoadedError, error="+t);
+       loadException = t;
+   }
+   
+
+   /** This is called from run on success or failure to mark the end
+    * of the load attempt. This must decrement the threadTaskCount or
+    * the ClassLoadingTaskDCL will never complete.
+    */
+   private synchronized void setLoadedClass(Class theClass, int order)
+   {
+      this.threadTaskCount --;
+      if( trace )
+         log.trace("setLoadedClass, theClass="+theClass+", order="+order);
+
+      // Warn about duplicate classes
+      if( this.loadedClass != null && order == loadOrder && theClass != null )
+      {
+         StringBuffer tmp = new StringBuffer("Duplicate class found: "+classname);
+         tmp.append('\n');
+         ProtectionDomain pd = this.loadedClass.getProtectionDomain();
+         CodeSource cs = pd != null ? pd.getCodeSource() : null;
+         tmp.append("Current CS: "+cs);
+         tmp.append('\n');
+         pd = theClass.getProtectionDomain();
+         cs = pd != null ? pd.getCodeSource() : null;
+         tmp.append("Duplicate CS: "+cs);
+         log.warn(tmp.toString());
+      }
+
+      // Accept the lowest order source of the class
+      if( theClass != null )
+      {
+         if( loadedClass == null || order <= loadOrder )
+         {
+            this.loadedClass = theClass;
+            this.loadOrder = order;
+         }
+         else
+         {
+            ProtectionDomain pd = this.loadedClass.getProtectionDomain();
+            CodeSource cs = pd != null ? pd.getCodeSource() : null;
+            ProtectionDomain pd2 = theClass.getProtectionDomain();
+            CodeSource cs2 = pd != null ? pd2.getCodeSource() : null;
+            log.debug("Ignoring source of: "+classname+" from CodeSource: "+cs2
+               +", due to order("+order+">="+loadOrder+"), "
+               +"accepted CodeSource: "+cs);
+         }
+      }
+   }
+}

Added: branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/DomainClassLoaderUCLImpl.java
===================================================================
--- branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/DomainClassLoaderUCLImpl.java	2006-08-29 02:01:28 UTC (rev 56380)
+++ branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/DomainClassLoaderUCLImpl.java	2006-08-29 02:02:32 UTC (rev 56381)
@@ -0,0 +1,352 @@
+package org.jboss.mx.loading;
+
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Enumeration;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.jboss.logging.Logger;
+import org.jboss.util.loading.Translatable;
+
+/**
+* A ClassLoader which loads classes from a single URL in conjunction with
+* the {@link LoaderRepositoryDomain}. Notice that this classloader does
+* not work independently of 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.
+*
+* At this point this is little more than an abstract class maintained as the
+* interface for class loaders as the algorithm of the UnifiedLoaderRepositoryDomain
+* fails with deadlocks, and several other class loading exceptions in multi-
+* threaded environments.
+*
+* @author <a href="marc.fleury at jboss.org">Marc Fleury</a>
+* @author <a href="christoph.jung at jboss.org">Christoph G. Jung</a>
+* @author <a href="scott.stark at jboss.org">Scott Stark</a>
+* @author <a href="juha at jboss.org">Juha Lindfors</a>
+* @author <a href="bill at jboss.org">Bill Burke</a>
+* @version <tt>$Revision: 44243 $</tt>
+*/
+public class DomainClassLoaderUCLImpl extends LegacyDomainClassLoader
+   implements UnifiedClassLoaderMBean, Translatable
+{
+   // Static --------------------------------------------------------
+
+   private static final Logger log = Logger.getLogger(UnifiedClassLoader.class);
+
+   // Attributes ----------------------------------------------------
+
+   /** One URL per ClassLoader in our case */
+   protected URL url = null;
+   /** An optional URL from which url may have been copied. It is used to
+    allow the security permissions to be based on a static url namespace. */
+   protected URL origURL = null;
+
+   // Constructors --------------------------------------------------
+   /**
+    * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
+    * classloader repository.
+    *
+    * @param url   the single URL to load classes from.
+    */
+   public DomainClassLoaderUCLImpl(URL url)
+   {
+      this(url, (URL) null);
+   }
+   /**
+    * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
+    * classloader repository.
+    *
+    * @param url   the single URL to load classes from.
+    * @param origURL the possibly null original URL from which url may
+    * be a local copy or nested jar.
+    */
+   public DomainClassLoaderUCLImpl(URL url, URL origURL)
+   {
+      this(url, origURL, UnifiedClassLoader.class.getClassLoader());
+   }
+
+   /**  Construct a UnifiedClassLoader without registering with the
+    * classloader repository.
+    *
+    * @param url   the single URL to load classes from.
+    * @param origURL the possibly null original URL from which url may
+    * be a local copy or nested jar.
+    * @param parent the parent class loader to use
+    */
+   public DomainClassLoaderUCLImpl(URL url, URL origURL, ClassLoader parent)
+   {
+      super(url == null ? new URL[]{} : new URL[] {url}, parent);
+
+      if (log.isTraceEnabled())
+         log.trace("New jmx UCL with url " + url);
+      this.url = url;
+      this.origURL = origURL;
+   }
+
+   /**
+    * 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 DomainClassLoaderUCLImpl(URL url, LoaderRepositoryDomain repository)
+   {
+      this(url, null, repository);
+   }
+   /**
+    * Construct a <tt>UnifiedClassLoader</tt> and registers it to the given
+    * repository.
+    * @param url The single URL to load classes from.
+    * @param origURL the possibly null original URL from which url may
+    * be a local copy or nested jar.
+    * @param repository the repository this classloader delegates to
+    * be a local copy or nested jar.
+    */
+   public DomainClassLoaderUCLImpl(URL url, URL origURL, LoaderRepositoryDomain repository)
+   {
+      this(url, origURL);
+
+      // set the repository reference
+      this.setDomain(repository);
+
+      // register this loader to the given repository
+      repository.addClassLoader(this);
+   }
+
+   /**
+    * UnifiedClassLoader constructor that can be used to
+    * register with a particular Loader Repository identified by ObjectName.
+    *
+    * @param url an <code>URL</code> value
+    * @param server a <code>MBeanServer</code> value
+    * @param repositoryName an <code>ObjectName</code> value
+    * @exception Exception if an error occurs
+    */
+   public DomainClassLoaderUCLImpl(final URL url, final MBeanServer server,
+      final ObjectName repositoryName) throws Exception
+   {
+      this(url, null, server, repositoryName);
+   }
+   /**
+    * UnifiedClassLoader constructor that can be used to
+    * register with a particular Loader Repository identified by ObjectName.
+    *
+    * @param url an <code>URL</code> value
+    * @param origURL the possibly null original URL from which url may
+    * be a local copy or nested jar.
+    * @param server a <code>MBeanServer</code> value
+    * @param repositoryName an <code>ObjectName</code> value
+    * @exception Exception if an error occurs
+    */
+   public DomainClassLoaderUCLImpl(final URL url, final URL origURL,
+      final MBeanServer server, final ObjectName repositoryName) throws Exception
+   {
+      this(url, origURL);
+      LoaderRepositoryDomain rep = (LoaderRepositoryDomain)server.invoke(repositoryName,
+                    "registerClassLoader",
+                    new Object[] {this},
+                    new String[] {getClass().getName()});
+      this.setDomain(rep);
+   }
+
+   // Public --------------------------------------------------------
+
+   /** Obtain the ObjectName under which the UCL can be registered with the
+    JMX server. This creates a name of the form "jmx.loading:UCL=hashCode"
+    since we don't currently care that UCL be easily queriable.
+    */
+   public ObjectName getObjectName() throws MalformedObjectNameException
+   {
+      String name = "jmx.loading:UCL="+Integer.toHexString(super.hashCode());
+      return new ObjectName(name);
+   }
+
+   public void unregister()
+   {
+      super.unregister();
+      this.origURL = null;
+      this.url = null;
+   }
+
+   /** Get the URL associated with the UCL.
+    */
+   public URL getURL()
+   {
+      return url;
+   }
+   
+   /** Get the original URL associated with the UCL. This may be null.
+    */
+   public URL getOrigURL()
+   {
+      return origURL;
+   }
+   
+   public synchronized Class loadClassImpl(String name, boolean resolve, int stopAt)
+      throws ClassNotFoundException
+   {
+      loadClassDepth ++;
+      boolean trace = log.isTraceEnabled();
+
+      if( trace )
+         log.trace("loadClassImpl, name="+name+", resolve="+resolve);
+      if( domain == null )
+      {
+         // If we have been undeployed we can still try locally
+         try
+         {
+            return super.loadClass(name, resolve);
+         }
+         catch (ClassNotFoundException ignored)
+         {
+         }
+         String msg = "Invalid use of destroyed classloader, UCL destroyed at:";
+         throw new ClassNotFoundException(msg, this.unregisterTrace);
+      }
+
+      /* Since loadClass can be called from loadClassInternal with the monitor
+         already held, we need to determine if there is a ClassLoadingTask
+         which requires this UCL. If there is, we release the UCL monitor
+         so that the ClassLoadingTask can use the UCL.
+       */
+      boolean acquired = attempt(1);
+      while( acquired == false )
+      {
+         /* Another thread needs this UCL to load a class so release the
+          monitor acquired by the synchronized method. We loop until
+          we can acquire the class loading lock.
+         */
+        try
+         {
+            if( trace )
+               log.trace("Waiting for loadClass lock");
+            this.wait();
+         }
+         catch(InterruptedException ignore)
+         {
+         }
+         acquired = attempt(1);
+      }
+
+      ClassLoadingTaskDCL task = null;
+      try
+      {
+         Thread t = Thread.currentThread();
+         // Register this thread as owning this UCL
+         if( loadLock.holds() == 1 )
+            LoadMgrDCL.registerLoaderThread(this, t);
+
+         // Create a class loading task and submit it to the repository
+         task = new ClassLoadingTaskDCL(name, this, t, stopAt);
+         /* Process class loading tasks needing this UCL until our task has
+            been completed by the thread owning the required UCL(s).
+          */
+         if( LoadMgrDCL.beginLoadTask(task, domain) == false )
+         {
+            while( task.threadTaskCount != 0 )
+            {
+               try
+               {
+                  LoadMgrDCL.nextTask(t, task, domain);
+               }
+               catch(InterruptedException e)
+               {
+                  // Abort the load or retry?
+                  break;
+               }
+            }
+         }
+      }
+      finally
+      {
+         // Unregister as the UCL owner to reschedule any remaining load tasks
+         if( loadLock.holds() == 1 )
+            LoadMgrDCL.endLoadTask(task);
+         // Notify any threads waiting to use this UCL
+         this.release();
+         this.notifyAll();
+         loadClassDepth --;
+      }
+
+      if( task.loadedClass == null )
+      {
+         if( task.loadException instanceof ClassNotFoundException )
+            throw (ClassNotFoundException) task.loadException;
+         else if( task.loadException instanceof NoClassDefFoundError )
+            throw (NoClassDefFoundError) task.loadException;
+         else if( task.loadException != null )
+         {
+            if( log.isTraceEnabled() )
+               log.trace("Unexpected error during load of:"+name, task.loadException);
+            String msg = "Unexpected error during load of: "+name
+               + ", msg="+task.loadException.getMessage();
+            ClassNotFoundException cnfe = new ClassNotFoundException(msg, task.loadException);
+            throw cnfe;
+         }
+         // Assert that loadedClass is not null
+         else
+            throw new IllegalStateException("ClassLoadingTask.loadedTask is null, name: "+name);
+      }
+
+      return task.loadedClass;
+   }
+
+   // URLClassLoader overrides --------------------------------------
+
+   /** Override the permissions accessor to use the CodeSource
+    based on the original URL if one exists. This allows the
+    security policy to be defined in terms of the static URL
+    namespace rather than the local copy or nested URL.
+    This builds a PermissionCollection from:
+    1. The origURL CodeSource
+    2. The argument CodeSource
+    3. The Policy.getPermission(origURL CodeSource)
+
+    This is necessary because we cannot define the CodeSource the
+    SecureClassLoader uses to register the class under.
+
+    @param cs the location and signatures of the codebase.
+    */
+   protected PermissionCollection getPermissions(CodeSource cs)
+   {
+      CodeSource permCS = cs;
+      if( origURL != null )
+      {
+         permCS = new CodeSource(origURL, cs.getCertificates());
+      }
+      Policy policy = Policy.getPolicy();
+      PermissionCollection perms = super.getPermissions(permCS);
+      PermissionCollection perms2 = super.getPermissions(cs);
+      PermissionCollection perms3 = policy.getPermissions(permCS);
+      Enumeration iter = perms2.elements();
+      while( iter.hasMoreElements() )
+         perms.add((Permission) iter.nextElement());
+      iter = perms3.elements();
+      while( iter.hasMoreElements() )
+         perms.add((Permission) iter.nextElement());
+      if( log.isTraceEnabled() )
+         log.trace("getPermissions, url="+url+", origURL="+origURL+" -> "+perms);
+      return perms;
+   }
+
+   /**
+    * Determine the protection domain. If we are a copy of the original
+    * deployment, use the original url as the codebase.
+    * @return the protection domain
+    * @todo certificates and principles?
+    */
+   protected ProtectionDomain getProtectionDomain()
+   {
+      return getProtectionDomain(origURL != null ? origURL : url);
+   }
+}
+

Copied: branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/LoadMgrDCL.java (from rev 56376, trunk/jmx/src/main/org/jboss/mx/loading/LoadMgr3.java)
===================================================================
--- trunk/jmx/src/main/org/jboss/mx/loading/LoadMgr3.java	2006-08-29 00:48:36 UTC (rev 56376)
+++ branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/LoadMgrDCL.java	2006-08-29 02:02:32 UTC (rev 56381)
@@ -0,0 +1,628 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.mx.loading;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+
+import org.jboss.classloading.spi.DomainClassLoader;
+import org.jboss.logging.Logger;
+import org.jboss.mx.loading.ClassLoadingTask.ThreadTask;
+
+
+/** A utility class used by the DomainClassLoaderUCLImpl to manage the thread
+ * based class loading tasks.
+ *
+ * @author Scott.Stark at jboss.org
+ * @version $Revision$
+ */
+public class LoadMgrDCL
+{
+   private static Logger log = Logger.getLogger(LoadMgrDCL.class);
+   /** Used as a synchronization monitor during the setup/teardown of the
+      thread owning a UCL.loadClass lock
+    */
+   private static Object registrationLock = new Object();
+
+   /** A Map<UnifiedClassLoader3, Thread> of the active loadClass UCL3/threads.
+    * This must be accessed under the registrationLock monitor.
+    */
+   private static HashMap loadClassThreads = new HashMap();
+   /** A Map<Thread, LinkedList<ThreadTask> > of the class loading tasks
+    * associated with a thread
+    */
+   private static Map loadTasksByThread = Collections.synchronizedMap(new WeakHashMap());
+
+   private static SecurityManager sm = System.getSecurityManager();
+
+   /** A UCL and its relative ordering with respect to the class loading.
+    * The UCL with the lowest order to load a class is the UCL that will
+    * populate the repository cache and be assigned as the UCL.loadClass
+    * return value.
+    */
+   public static class PkgClassLoader
+   {
+      public final RepositoryClassLoader ucl;
+      public final int order;
+
+      public PkgClassLoader(RepositoryClassLoader ucl)
+      {
+         this(ucl, Integer.MAX_VALUE);
+      }
+      public PkgClassLoader(RepositoryClassLoader ucl, int order)
+      {
+         this.ucl = ucl;
+         this.order = order;
+      }
+      
+      public String toString()
+      {
+         StringBuffer buffer = new StringBuffer(100);
+         buffer.append(super.toString());
+         buffer.append("{ucl=").append(ucl);
+         buffer.append(" order=").append(order);
+         buffer.append('}');
+         return buffer.toString();
+      }
+   }
+   /** A PrivilegedAction for locating a class as a resource
+    * 
+    */ 
+   private static class ResourceAction implements PrivilegedAction
+   {
+      RepositoryClassLoader ucl;
+      String classRsrcName;
+      ResourceAction(RepositoryClassLoader ucl, String classRsrcName)
+      {
+         this.ucl = ucl;
+         this.classRsrcName = classRsrcName;
+      }
+      public Object run()
+      {
+         URL url = ucl.getResourceLocally(classRsrcName);
+         ucl = null;
+         classRsrcName = null;
+         return url;
+      }
+   }
+
+   /** Register that a thread owns the UCL3.loadClass monitor. This is called
+    * from within UCL3.loadClass(String,boolean) and this method creates
+    * entries in the loadClassThreads and loadTasksByThread maps.
+    */
+   public static void registerLoaderThread(DomainClassLoader ucl, Thread t)
+   {
+      synchronized( registrationLock )
+      {
+         Object prevThread = loadClassThreads.put(ucl, t);
+         if( log.isTraceEnabled() )
+            log.trace("registerLoaderThread, ucl="+ucl+", t="+t+", prevT="+prevThread);
+
+         synchronized( loadTasksByThread )
+         {
+            List taskList = (List) loadTasksByThread.get(t);
+            if( taskList == null )
+            {
+               taskList = Collections.synchronizedList(new LinkedList());
+               loadTasksByThread.put(t, taskList);
+               if( log.isTraceEnabled() )
+                  log.trace("created new task list");
+            }
+         }
+         registrationLock.notifyAll();
+      }
+   }
+
+   /** Initiate the class loading task. This is called by UCL3.loadClass to
+    * initiate the process of loading the requested class. This first attempts
+    * to load the class from the repository cache, and then the class loaders
+    * in the repsository. If the package of the class is found in the repository
+    * then one or more ThreadTask are created to complete the ClassLoadingTask.
+    * The ThreadTask are assigned to the threads that own the associated UCL3
+    * monitor. If no class loader serves the class package, then the requesting
+    * class loader is asked if it can load the class.
+    *
+    * @return true if the class could be loaded from the cache or requesting
+    * UCL3, false to indicate the calling thread must process the
+    * tasks assigned to it until the ClassLoadingTask state is FINISHED
+    * @exception ClassNotFoundException if there is no chance the class can
+    * be loaded from the current repository class loaders.
+    */
+   public static boolean beginLoadTask(ClassLoadingTask task,
+      UnifiedLoaderRepository3 repository)
+      throws ClassNotFoundException
+   {
+      boolean trace = log.isTraceEnabled();
+      if( trace )
+         log.trace("Begin beginLoadTask, task="+task);
+
+      // Try the cache before anything else.
+      Class cls = repository.loadClassFromCache(task.classname);
+      if( cls != null )
+      {
+         task.loadedClass = cls;
+         task.state = ClassLoadingTask.FINISHED;
+         if( trace )
+            log.trace("End beginLoadTask, loadClassFromCache, classname: "+task.classname);
+         return true;
+      }
+
+      // Next get the set of class loaders from the packages map
+      Set pkgSet = repository.getPackageClassLoaders(task.classname);
+      if( pkgSet == null || pkgSet.size() == 0 )
+      {
+         if (task.stopOrder == Integer.MAX_VALUE)
+         {
+            /* If there are no class loaders in the repository capable of handling
+            the request ask the class loader itself in the event that its parent(s)
+            can load the class.
+            */
+            try
+            {
+               cls = repository.loadClassFromClassLoader(task.classname, false,
+                  task.requestingClassLoader);
+            }
+            catch(LinkageError e)
+            {
+               if( trace )
+                  log.trace("End beginLoadTask, LinkageError for task: "+task, e);
+               throw e;
+            }
+            if( cls != null )
+            {
+               task.loadedClass = cls;
+               task.state = ClassLoadingTask.FINISHED;
+               if( trace )
+                  log.trace("End beginLoadTask, loadClassFromClassLoader");
+               return true;
+            }
+         }
+
+         // Else, fail the load
+         if( trace )
+            log.trace("End beginLoadTask, ClassNotFoundException");
+         String msg = "No ClassLoaders found for: "+task.classname;
+         throw new ClassNotFoundException(msg);
+      }
+
+      /* A class loading task for each ClassLoader is needed. There can be
+         multiple class loaders for a pkg due to the pkg being spread out over
+         multiple jars, or duplicate classes due to versioning/patches, or
+         just bad packaging.
+
+         In the case of a non-scoped deployment of multiple classes which
+         will provide a PkgClassLoader to define the ordering, we simply
+         choose an ordering based on the order the UCL3s were added to the
+         repository. At most one of the candidate UCL3s will load the class
+         in order to avoid ClassCastExceptions or LinkageErrors due to the
+         strong Java type system/security model.
+
+         TODO: A simple ordering mechanism exists, but this probably needs
+         to be augmented.
+       */
+      Iterator iter = pkgSet.iterator();
+      RepositoryClassLoader theUCL = null;
+      int order = Integer.MAX_VALUE;
+      while( iter.hasNext() )
+      {
+         Object next = iter.next();
+         int uclOrder;
+         RepositoryClassLoader ucl;
+         // This may be either a PkgClassLoader or a UCL3
+         if( next instanceof RepositoryClassLoader )
+         {
+            ucl = (RepositoryClassLoader) next;
+            uclOrder = ucl.getAddedOrder();
+         }
+         else
+         {
+            PkgClassLoader pkgUcl = (PkgClassLoader) next;
+            ucl = pkgUcl.ucl;
+            uclOrder = pkgUcl.order;
+         }
+
+         // If we have a stop order check it
+         if (task.stopOrder != Integer.MAX_VALUE && task.stopOrder <= uclOrder)
+            break;
+         
+         // Validate that the ucl has the class as a resource
+         String classRsrcName = task.classname.replace('.', '/') + ".class";
+         URL url = null;
+         if( sm != null )
+         {
+            ResourceAction action = new ResourceAction(ucl, classRsrcName);
+            url = (URL) AccessController.doPrivileged(action);
+         }
+         else
+         {
+            url = ucl.getResourceLocally(classRsrcName);
+         }
+
+         if( url != null && uclOrder < order )
+         {
+            if( trace && theUCL != null )
+               log.trace("Replacing UCL: "+theUCL+" with UCL:"+ucl);
+            theUCL = ucl;
+            order = uclOrder;
+         }
+      }
+      if( theUCL == null && task.stopOrder == Integer.MAX_VALUE)
+      {
+         /* If there are no class loaders in the repository capable of handling
+         the request ask the class loader itself in the event that its parent(s)
+         can load the class. But not if we have a stopOrder.
+         */
+         try
+         {
+            cls = repository.loadClassFromClassLoader(task.classname, false,
+               task.requestingClassLoader);
+         }
+         catch(LinkageError e)
+         {
+            if( trace )
+               log.trace("End beginLoadTask, LinkageError for task: "+task, e);
+            throw e;
+         }
+         if( cls != null )
+         {
+            task.loadedClass = cls;
+            task.state = ClassLoadingTask.FINISHED;
+            if( trace )
+               log.trace("End beginLoadTask, loadClassFromClassLoader");
+            return true;
+         }
+
+         // Else, fail the load
+         if( trace )
+            log.trace("End beginLoadTask, ClassNotFoundException");
+         String msg = "No ClassLoaders found for: "+task.classname;
+         throw new ClassNotFoundException(msg);
+      }
+
+      if (theUCL == null)
+      {
+         if( trace )
+            log.trace("End beginLoadTask, ClassNotFoundException");
+         String msg = "No ClassLoaders found for: "+task.classname;
+         throw new ClassNotFoundException(msg);
+      }
+
+      scheduleTask(task, theUCL, order, false, trace);
+      task.state = ClassLoadingTask.FOUND_CLASS_LOADER;
+      if( trace )
+         log.trace("End beginLoadTask, task="+task);
+
+      return false;
+   }
+
+   /** Called by threads owning a UCL3.loadLock from within UCL3.loadClass to
+    * process ThreadTasks assigned to them. This is the mechanism by which we
+    * avoid deadlock due to a given loadClass request requiring multiple UCLs
+    * to be involved. Any thread active in loadClass with the monitor held
+    * processes class loading tasks that must be handled by its UCL3. The
+    * active set of threads loading classes form a pool of cooperating threads.
+    */
+   public static void nextTask(Thread t, ClassLoadingTask task,
+      UnifiedLoaderRepository3 repository)
+      throws InterruptedException
+   {
+      boolean trace = log.isTraceEnabled();
+      List taskList = (List) loadTasksByThread.get(t);
+      synchronized( taskList )
+      {
+         // There may not be any ThreadTasks
+         while( taskList.size() == 0 && task.threadTaskCount != 0 )
+         {
+            /* There are no more tasks for the calling thread to execute, so the
+            calling thread must wait until the task.threadTaskCount reaches 0
+             */
+            if( trace )
+               log.trace("Begin nextTask(WAIT_ON_EVENT), task="+task);
+            try
+            {
+               task.state = ClassLoadingTask.WAIT_ON_EVENT;
+               taskList.wait();
+            }
+            catch(InterruptedException e)
+            {
+               if( trace )
+                  log.trace("nextTask(WAIT_ON_EVENT), interrupted, task="+task, e);
+               // Abort this task attempt
+               throw e;
+            }
+            if( trace )
+               log.trace("nextTask(WAIT_ON_EVENT), notified, task="+task);
+         }
+
+         if( trace )
+            log.trace("Continue nextTask("+taskList.size()+"), task="+task);
+
+         // See if the task is complete
+         if( task.threadTaskCount == 0 )
+         {
+            task.state = ClassLoadingTask.FINISHED;
+            log.trace("End nextTask(FINISHED), task="+task);
+            return;
+         }
+      }
+
+      ThreadTask threadTask = (ThreadTask) taskList.remove(0);
+      ClassLoadingTask loadTask = threadTask.getLoadTask();
+      if( trace )
+         log.trace("Begin nextTask("+taskList.size()+"), loadTask="+loadTask);
+
+      RepositoryClassLoader ucl3 = threadTask.ucl;
+      try
+      {
+         if( threadTask.t == null )
+         {
+            /* This is a task that has been reassigned back to the original
+            requesting thread ClassLoadingTask, so a new ThreadTask must
+            be scheduled.
+            */
+            if( trace )
+               log.trace("Rescheduling threadTask="+threadTask);
+            scheduleTask(loadTask, ucl3, threadTask.order, true, trace);
+         }
+         else
+         {
+            if( trace )
+               log.trace("Running threadTask="+threadTask);
+            // Load the class using this thread
+            threadTask.run();
+         }
+      }
+      catch(Throwable e)
+      {
+         if( e instanceof ClassCircularityError /*&& taskList.size() > 0 */ )
+         {
+            /* Reschedule this task after all existing tasks to allow the
+            current load tasks which are conflicting to complete.
+            */
+            try
+            {
+               if( trace )
+                  log.trace("Run failed with exception", e);
+               // Reschedule and update the loadTask.threadTaskCount
+               scheduleTask(loadTask, ucl3, Integer.MAX_VALUE, true, trace);
+            }
+            catch(ClassNotFoundException ex)
+            {
+               loadTask.setLoadError(ex);
+               log.warn("Failed to reschedule task after CCE", ex);
+            }
+            if( trace )
+               log.trace("Post CCE state, loadTask="+loadTask);
+         }
+         else
+         {
+            loadTask.setLoadError(e);
+            if( trace )
+               log.trace("Run failed with exception", e);
+         }
+      }
+      finally
+      {
+         // We must release the loadLock acquired in beginLoadTask
+         if( threadTask.releaseInNextTask == true )
+         {
+            if( trace )
+               log.trace("Releasing loadLock and ownership of UCL: "+threadTask.ucl);
+            synchronized( registrationLock )
+            {
+               loadClassThreads.remove(threadTask.ucl);
+            }
+            synchronized( threadTask.ucl )
+            {
+               ucl3.release();
+               ucl3.notifyAll();
+            }
+         }
+      }
+
+      // If the ThreadTasks are complete mark the ClassLoadingTask finished
+      if( loadTask.threadTaskCount == 0 )
+      {
+         Class loadedClass = threadTask.getLoadedClass();
+         if( loadedClass != null )
+         {
+            ClassLoader loader = loadedClass.getClassLoader();
+            ClassLoader wrapper = repository.getWrappingClassLoader(loader);
+            if (wrapper != null)
+               loader=wrapper;
+            // Place the loaded class into the repositry cache
+            repository.cacheLoadedClass(threadTask.getClassname(),
+               loadedClass, loader);
+         }
+         /*
+         synchronized( loadTask )
+         {
+            if( trace )
+               log.trace("Notifying task of thread completion, loadTask:"+loadTask);
+            loadTask.state = ClassLoadingTask.FINISHED;
+            loadTask.notify();
+         }
+         */
+         List loadTaskThreadTasks = (List) loadTasksByThread.get(loadTask.requestingThread);
+         synchronized( loadTaskThreadTasks )
+         {
+            if( trace )
+               log.trace("Notifying task of thread completion, loadTask:"+loadTask);
+            loadTask.state = ClassLoadingTask.FINISHED;
+            loadTaskThreadTasks.notify();
+         }
+      }
+      if( trace )
+         log.trace("End nextTask("+taskList.size()+"), loadTask="+loadTask);
+   }
+
+   /** Complete a ClassLoadingTask. This is called by UCL3.loadClass to indicate
+    * that the thread is existing the loadClass method.
+    */
+   public static void endLoadTask(ClassLoadingTask task)
+   {
+      boolean trace = log.isTraceEnabled();
+      if( trace )
+         log.trace("Begin endLoadTask, task="+task);
+
+      // Unregister as the owning thread and notify any waiting threads
+      synchronized( registrationLock )
+      {
+         loadClassThreads.remove(task.requestingClassLoader);
+         registrationLock.notifyAll();
+      }
+
+      // Any ThreadTasks associated with this thread must be reassigned
+      List taskList = (List) loadTasksByThread.get(task.requestingThread);
+      int size = taskList != null ? taskList.size() : 0;
+      synchronized( taskList )
+      {
+         for(int i = 0; i < size; i ++)
+         {
+            ThreadTask threadTask = (ThreadTask) taskList.remove(0);
+            ClassLoadingTask loadTask = threadTask.getLoadTask();
+            /* Synchronize on loadTask and reassign the thread task back to the
+            requesting thread of loadTask. We need to synchronize on loadTask
+            to ensure that the transfer of this task back to loadTask.requestingThread
+            is atomic wrt loadTask.requestingThread checking its task list.
+            synchronized( loadTask )
+            {
+               if( trace )
+                  log.trace("Reassigning task: "+threadTask+", to: "+loadTask.requestingThread);
+               threadTask.t = null;
+               // Insert the task into the front of requestingThread task list
+               List toTaskList = (List) loadTasksByThread.get(loadTask.requestingThread);
+               toTaskList.add(0, threadTask);
+               loadTask.state = ClassLoadingTask.NEXT_EVENT;
+               loadTask.notify();
+            }
+            */
+            if( trace )
+               log.trace("Reassigning task: "+threadTask+", to: "+loadTask.requestingThread);
+            threadTask.t = null;
+            // Insert the task into the front of requestingThread task list
+            List toTaskList = (List) loadTasksByThread.get(loadTask.requestingThread);
+            synchronized( toTaskList )
+            {
+               toTaskList.add(0, threadTask);
+               loadTask.state = ClassLoadingTask.NEXT_EVENT;
+               toTaskList.notify();
+            }
+         }
+      }
+   }
+
+   /** Invoked to create a ThreadTask to assign a thread to the task of
+    * loading the class of ClassLoadingTask.
+    *
+    * @param task the orginating UCL3.loadClass task for which the thread
+    * @param ucl the UCL3 the ThreadTask will call loadClassLocally on
+    * @param order the heirachical ordering of the task
+    * @param reschedule a boolean indicating if this task is being rescheduled
+    *    with another UCL3
+    * @param trace the Logger trace level flag
+    * @throws ClassNotFoundException
+    */
+   static private void scheduleTask(ClassLoadingTask task, RepositoryClassLoader ucl,
+      int order, boolean reschedule, boolean trace) throws ClassNotFoundException
+   {
+      Thread t = null;
+      boolean releaseInNextTask = false;
+      ThreadTask subtask = null;
+      List taskList = null;
+      synchronized( registrationLock )
+      {
+         // Find the thread that owns the ucl
+         t = (Thread) loadClassThreads.get(ucl);
+         if( t == null )
+         {
+            /* There is no thread in the UCL.loadClass yet that has registered
+               as the owning thread. We must attempt to acquire the loadLock
+               and if we cannot, wait until the thread entering UCL.loadClass
+               gets to the registerLoaderThread call. By the time we are
+               notified, the thread coule in fact have exited loadClass, so
+               we either assign the task to the thread, or take ownership of
+               the UCL.
+             */
+            while( t == null && ucl.attempt(1) == false )
+            {
+               if( trace )
+                  log.trace("Waiting for owner of UCL: "+ucl);
+               try
+               {
+                  registrationLock.wait();
+               }
+               catch(InterruptedException e)
+               {
+                  String msg = "Interrupted waiting for registration notify,"
+                     + " classame: "+task.classname;
+                  throw new ClassNotFoundException(msg);
+               }
+
+               t = (Thread) loadClassThreads.get(ucl);
+               if( trace )
+                  log.trace("Notified that UCL owner is: "+t);
+            }
+
+            // Get the thread registered as owning the UCL.loadClass lock
+            t = (Thread) loadClassThreads.get(ucl);
+            if( t == null )
+            {
+               // There is no such thread, register as the owner
+               releaseInNextTask = true;
+               t = task.requestingThread;
+               Object prevThread = loadClassThreads.put(ucl, t);
+               if( trace )
+               {
+                  log.trace("scheduleTask, taking ownership of ucl="+ucl
+                     +", t="+t+", prevT="+prevThread);
+               }
+            }
+         }
+
+         // Now that we have the UCL owner thread, create and assign the task
+         subtask = task.newThreadTask(ucl, t, order, reschedule,
+            releaseInNextTask);
+         // Add the task to the owning thread
+         taskList = (List) loadTasksByThread.get(t);
+         synchronized( taskList )
+         {
+            taskList.add(subtask);
+            // Order the tasks by either the heirarchial order, or the repository order
+            Collections.sort(taskList, task.taskComparator);
+            taskList.notify();
+         }
+      }
+
+      if( trace )
+         log.trace("scheduleTask("+taskList.size()+"), created subtask: "+subtask);
+   }
+}

Added: branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCL.java
===================================================================
--- branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCL.java	2006-08-29 02:01:28 UTC (rev 56380)
+++ branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCL.java	2006-08-29 02:02:32 UTC (rev 56381)
@@ -0,0 +1,1023 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.mx.loading;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Set;
+import java.io.IOException;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.MBeanRegistration;
+import javax.management.ObjectName;
+import javax.management.MBeanServer;
+import javax.management.loading.MLet;
+
+import org.jboss.classloading.spi.ClassLoadingDomain;
+import org.jboss.classloading.spi.DomainClassLoader;
+import org.jboss.logging.Logger;
+import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
+import org.jboss.util.Classes;
+
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
+import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArraySet;
+
+/** A repository of class loaders that form a flat namespace of classes
+ * and resources. This version uses DomainClassLoaderUCLImpl instances. Class
+ * and resource loading is synchronized by the acquiring the monitor to the
+ * associated repository structure monitor. See the variable javadoc comments
+ * for what monitor is used to access a given structure.
+ *
+ * @author  <a href="mailto:scott.stark at jboss.org">Scott Stark</a>.
+ * @author  <a href="mailto:Adrian.Brock at HappeningTimes.com">Adrian Brock</a>.
+ * @version $Revision: 37459 $
+ * just a hint... xdoclet not really used
+ * @jmx.name="JMImplementation:service=UnifiedLoaderRepository,name=Default"
+ */
+public class UnifiedLoaderRepositoryDCL extends LoaderRepositoryDomain
+   implements MBeanRegistration, NotificationBroadcaster,
+   UnifiedLoaderRepositoryDCLMBean
+{
+   // Static --------------------------------------------------------
+   private static final Logger log = Logger.getLogger(UnifiedLoaderRepository3.class);
+   /** Used to provide a relative ordering of UCLs based on the order in
+    * which they are added to the repository */
+   private static int addedCount;
+
+   // Attributes ----------------------------------------------------
+
+   /** HashSet<UCL> of classloaders in the repository.
+    * Access synchronized via this.classLoaders monitor.
+    */
+   private CopyOnWriteArraySet classLoaders = new CopyOnWriteArraySet();
+   /** HashSet<UCL> of class loaders in the repository that have a dynamic
+    * URL associated with them. Such a class loader is added to every package
+    * class loader set in #getPackageClassLoaders(String).
+    */
+   private HashSet dynamicClassLoaders = new HashSet();
+   /** A HashMap<DomainClassLoader, UCL> of foreign (non-UCL) classloaders that
+    * have been added to the repository as the key and the value the UCL
+    * actually used by the ULR.
+    * Access synchronized via this.classLoaders monitor.
+    */
+   private HashMap nonUCLClassLoader = new HashMap();
+
+   /** A HashSet<URL> used to check for duplicate URLs. Previously this was handled
+    by the UCL.equals, but this caused problems with Class.forName(String,
+    boolean, DomainClassLoader) caching.
+    Access synchronized via this.classLoaders monitor.
+    */
+   private HashSet classLoaderURLs = new HashSet();
+
+   /** The loaded classes cache, HashMap<String, Class>.
+    * Access synchronized via this.classes monitor.
+    */
+   private ConcurrentReaderHashMap classes = new ConcurrentReaderHashMap();
+
+   /** HashMap<UCL, HashSet<String>> class loaders to the set of class names
+    * loaded via the UCL.
+    * Access synchronized via this.classes monitor.
+    */
+   private HashMap loaderToClassesMap = new HashMap();
+
+   /** HashMap<UCL, HashMap<String, URL>> class loaders to the set of
+    * resource names they looked up.
+    * Access synchronized via this.loaderToResourcesMap monitor.
+    */
+   private HashMap loaderToResourcesMap = new HashMap();
+
+   /** HashMap<String, ResourceInfo(URL, UCL)> of global resources not unique
+    * to a UCL
+    * Access synchronized via this.loaderToResourcesMap monitor.
+    */
+   private HashMap globalResources = new HashMap();
+
+   /** A HashMap<String, Set<UCL>> of package names to the set of
+    * ClassLoaders which have classes in the package.
+    * Access synchronized via this.packagesMap monitor.
+    */
+   private ConcurrentReaderHashMap packagesMap = new ConcurrentReaderHashMap();
+
+   /** A HashMap<UCL, String[]> of class loaders to the array of pckages names
+    * they serve
+    * Access synchronized via this.packagesMap monitor.
+    */
+   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 JBossNotificationBroadcasterSupport broadcaster = new JBossNotificationBroadcasterSupport();
+
+   /**
+    * The NotificationInfo we emit.
+    */
+   private MBeanNotificationInfo[] info;
+
+
+   // Public --------------------------------------------------------
+
+   public DomainClassLoader newClassLoader(final URL url, boolean addToRepository)
+           throws Exception
+   {
+      DomainClassLoaderUCLImpl ucl = new DomainClassLoaderUCLImpl(url, null, this);
+      if (addToRepository)
+         this.registerClassLoader(ucl);
+      return ucl;
+   }
+
+   public DomainClassLoader newClassLoader(final URL url, final URL origURL, boolean addToRepository)
+           throws Exception
+   {
+      DomainClassLoaderUCLImpl ucl = new DomainClassLoaderUCLImpl(url, origURL, this);
+      if (addToRepository)
+         this.registerClassLoader(ucl);
+      return ucl;
+   }
+
+   public ClassLoadingDomain getParent()
+   {
+      return null;
+   }
+
+   public int getCacheSize()
+   {
+      return classes.size();
+   }
+
+   public int getClassLoadersSize()
+   {
+      return classLoaders.size();
+   }
+
+   public void flush()
+   {
+      synchronized (classes)
+      {
+         classes.clear();
+      }
+   }
+
+   public Class getCachedClass(String classname)
+   {
+      return (Class) classes.get(classname);
+   }
+
+   /** Unlike other implementations of LoaderRepository, this method does
+    * nothing but ask the DomainClassLoaderUCLImpl to load the class as UCL3s
+    * do not use this method.
+    */
+   public Class loadClass(String name, boolean resolve, DomainClassLoader cl) throws ClassNotFoundException
+   {
+      return cl.loadClass(name);
+   }
+
+   /** Called by LoadMgr to obtain all class loaders for the given className
+    * @return Set<DomainClassLoaderUCLImpl>, may be null
+    */
+   public Set getPackageClassLoaders(String className)
+   {
+      String pkgName = ClassLoaderUtils.getPackageName(className);
+      Set pkgSet = (Set) packagesMap.get(pkgName);
+      if (dynamicClassLoaders.size() > 0)
+      {
+         if (pkgSet == null)
+            pkgSet = ClassLoaderUtils.newPackageSet();
+         pkgSet.addAll(dynamicClassLoaders);
+      }
+      return pkgSet;
+   }
+
+   private String getResourcePackageName(String rsrcName)
+   {
+      int index = rsrcName.lastIndexOf('/');
+      String pkgName = rsrcName;
+      if (index > 0)
+         pkgName = rsrcName.substring(0, index);
+      return pkgName.replace('/', '.');
+   }
+
+   /** Lookup a Class from the repository cache.
+    * @param name the fully qualified class name
+    * @return the cached Class if found, null otherwise
+    */
+   public Class loadClassFromCache(String name)
+   {
+      Class cls = null;
+      synchronized (classes)
+      {
+         cls = (Class) classes.get(name);
+      }
+      return cls;
+   }
+
+   /** Add a Class to the repository cache.
+    * @param name the fully qualified class name
+    * @param cls the Class instance
+    * @param cl the repository UCL
+    */
+   public void cacheLoadedClass(String name, Class cls, DomainClassLoader cl)
+   {
+      synchronized (classes)
+      {
+         // Update the global cache
+         Object prevClass = classes.put(name, cls);
+         if (log.isTraceEnabled())
+         {
+            log.trace("cacheLoadedClass, classname: " + name + ", class: " + cls
+                    + ", ucl: " + cl + ", prevClass: " + prevClass);
+         }
+
+         // Update the cache for this classloader
+         // This is used to cycling classloaders
+         HashSet loadedClasses = (HashSet) loaderToClassesMap.get(cl);
+         if (loadedClasses == null)
+         {
+            loadedClasses = new HashSet();
+            loaderToClassesMap.put(cl, loadedClasses);
+         }
+         loadedClasses.add(name);
+      }
+   }
+
+   Class loadClassFromClassLoader(String name, boolean resolve, DomainClassLoader cl)
+   {
+      try
+      {
+         Class cls = cl.loadClassLocally(name, resolve);
+         cacheLoadedClass(name, cls, cl);
+         return cls;
+      }
+      catch (ClassNotFoundException x)
+      {
+         // The class is not visible by the calling classloader
+      }
+      return null;
+   }
+
+   /**
+    * Loads a resource following the Unified DomainClassLoader architecture
+    */
+   public URL getResource(String name, DomainClassLoader 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;
+   }
+
+   /** Find all resource URLs for the given name. This is entails an
+    * exhuastive search of the repository and is an expensive operation.
+    *
+    * @param name the resource name
+    * @param cl the requesting class loader
+    * @param urls a list into which the located resource URLs will be placed
+    */
+   public void getResources(String name, DomainClassLoader cl, List urls)
+   {
+      // Go through all class loaders
+      Iterator iter = classLoaders.iterator();
+      while (iter.hasNext() == true)
+      {
+         DomainClassLoader nextCL = (DomainClassLoader) iter.next();
+         if (nextCL instanceof DomainClassLoader)
+         {
+            DomainClassLoader ucl = (DomainClassLoader) nextCL;
+            try
+            {
+               Enumeration resURLs = ucl.loadResourceLocally(name);
+               while (resURLs.hasMoreElements())
+               {
+                  Object res = resURLs.nextElement();
+                  urls.add(res);
+               }
+            }
+            catch (IOException ignore)
+            {
+            }
+         }
+      }
+   }
+
+   /** As opposed to classes, resource are not looked up in a global cache,
+    * since 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
+    * @param name the resource name
+    * @param cl the repository classloader
+    * @return the resource URL if found, null otherwise
+    */
+   private URL getResourceFromCache(String name, DomainClassLoader cl)
+   {
+      URL resource = null;
+      synchronized (loaderToResourcesMap)
+      {
+         if (loaderToResourcesMap.containsKey(cl))
+         {
+            HashMap resources = (HashMap) loaderToResourcesMap.get(cl);
+            resource = (URL) resources.get(name);
+         }
+      }
+      return resource;
+   }
+
+   private URL getResourceFromClassLoader(String name, DomainClassLoader cl)
+   {
+      URL resource = null;
+      if (cl instanceof DomainClassLoader)
+      {
+         DomainClassLoader ucl = (DomainClassLoader) cl;
+         resource = ucl.loadResourceLocally(name);
+         cacheLoadedResource(name, resource, cl);
+      }
+      return resource;
+   }
+
+   /** Check for a resource in the global cache
+    * Synchronizes access to globalResources using the loaderToResourcesMap monitor
+    * @param name
+    * @return
+    */
+   protected URL getResourceFromGlobalCache(String name)
+   {
+      ResourceInfo ri = null;
+      synchronized (loaderToResourcesMap)
+      {
+         ri = (ResourceInfo) globalResources.get(name);
+      }
+      URL resource = null;
+      if (ri != null)
+         resource = ri.url;
+      return resource;
+   }
+
+   protected URL getResourceFromRepository(String name, DomainClassLoader cl)
+   {
+      // Get the set of class loaders from the packages map
+      String pkgName = getResourcePackageName(name);
+      Iterator i = null;
+      Set pkgSet = (Set) this.packagesMap.get(pkgName);
+      if (pkgSet != null)
+      {
+         i = pkgSet.iterator();
+      }
+      if (i == null)
+      {
+         // If no pkg match was found just go through all class loaders
+         i = classLoaders.iterator();
+      }
+
+      URL url = null;
+      while (i.hasNext() == true)
+      {
+         DomainClassLoader classloader = (DomainClassLoader) i.next();
+         if (classloader.equals(cl))
+         {
+            continue;
+         }
+
+         if (classloader instanceof DomainClassLoader)
+         {
+            url = ((DomainClassLoader) classloader).loadResourceLocally(name);
+            if (url != null)
+            {
+               cacheLoadedResource(name, url, classloader);
+               cacheGlobalResource(name, url, classloader);
+               break;
+            }
+            else
+            {
+               // Do nothing, go on with next classloader
+            }
+         }
+      }
+      return url;
+   }
+
+   /** Update the loaderToResourcesMap
+    * @param name the resource name
+    * @param url the resource URL
+    * @param cl the UCL
+    */
+   private void cacheLoadedResource(String name, URL url, DomainClassLoader cl)
+   {
+      // Update the cache for this classloader only
+      // This is used for cycling classloaders
+      synchronized (loaderToResourcesMap)
+      {
+         HashMap resources = (HashMap) loaderToResourcesMap.get(cl);
+         if (resources == null)
+         {
+            resources = new HashMap();
+            loaderToResourcesMap.put(cl, resources);
+         }
+         resources.put(name, url);
+      }
+   }
+
+   /** Update cache of resources looked up via one UCL, buf found in another UCL
+    * @param name the resource name
+    * @param url the resource URL
+    * @param cl the UCL
+    */
+   private void cacheGlobalResource(String name, URL url, DomainClassLoader cl)
+   {
+      synchronized (loaderToResourcesMap)
+      {
+         globalResources.put(name, new ResourceInfo(url, cl));
+      }
+   }
+
+   /** This is a utility method a listing of the URL for all UnifiedClassLoaders
+    * associated with the repository. It is never called in response to
+    * class or resource loading.
+    */
+   public URL[] getURLs()
+   {
+      HashSet classpath = new HashSet();
+      Set tmp = classLoaders;
+      for (Iterator iter = tmp.iterator(); iter.hasNext();)
+      {
+         Object obj = iter.next();
+         if (obj instanceof DomainClassLoader)
+         {
+            DomainClassLoader cl = (DomainClassLoader) 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
+
+      URL[] cp = new URL[classpath.size()];
+      classpath.toArray(cp);
+      return cp;
+   }
+
+   /** A utility method that iterates over all repository class loaders and
+    * display the class information for every UCL that contains the given
+    * className
+    */
+   public String displayClassInfo(String className)
+   {
+      /* 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 = className.replace('.', '/') + ".class";
+
+      int count = 0;
+      Class loadedClass = this.loadClassFromCache(className);
+      StringBuffer results = new StringBuffer(className + " Information\n");
+      if (loadedClass != null)
+      {
+         results.append("Repository cache version:");
+         Classes.displayClassInfo(loadedClass, results);
+      }
+      else
+      {
+         results.append("Not loaded in repository cache\n");
+      }
+      Set tmp = classLoaders;
+      for (Iterator iter = tmp.iterator(); iter.hasNext();)
+      {
+         URLClassLoader cl = (URLClassLoader) iter.next();
+         URL classURL = cl.findResource(classRsrcName);
+         if (classURL != null)
+         {
+            results.append("\n\n### Instance" + count + " found in UCL: " + cl + "\n");
+            count++;
+         }
+      }
+
+      // Also look to the parent class loaders of the TCL
+      ClassLoader tcl = Thread.currentThread().getContextClassLoader();
+      URLClassLoader[] stack = ClassLoaderUtils.getClassLoaderStack(tcl);
+      for (int s = 0; s < stack.length; s++)
+      {
+         URLClassLoader cl = stack[s];
+         URL classURL = cl.findResource(classRsrcName);
+         if (classURL != null)
+         {
+            results.append("\n\n### Instance" + count + " via UCL: " + cl + "\n");
+            count++;
+         }
+      }
+
+      return results.toString();
+   }
+
+   // LoaderRepository overrides ------------------------------------
+
+   /** First tries to load from any UCL in the ULR, and if the
+    * class is not found, next tries the current thread context
+    * class loader.
+    * @param className - the class to load
+    */
+   public Class loadClass(String className) throws ClassNotFoundException
+   {
+      // Try to load from a UCL in the ULR first
+      ClassLoader scl = Thread.currentThread().getContextClassLoader();
+      DomainClassLoader ucl = null;
+      if (classLoaders.size() > 0)
+         ucl = (DomainClassLoader) this.classLoaders.iterator().next();
+      try
+      {
+         if (ucl != null)
+            return loadClass(className, false, ucl);
+      }
+      catch (ClassNotFoundException ignore)
+      {
+         // go on and try the next loader
+      }
+
+      try
+      {
+         // If there is no class try the TCL
+         return scl.loadClass(className);
+      }
+      catch (ClassNotFoundException e)
+      {
+         // go on and try the next loader
+      }
+
+      // at last try a native
+      Class clazz = getNativeClassForName(className);
+      if (clazz != null) return clazz;
+
+      throw new ClassNotFoundException(className);
+   }
+
+   /**
+    * Loads a class from the repository, excluding the given
+    * classloader.
+    *
+    * @param loader the classloader to exclude
+    * @param className the class to load
+    * @return the found class
+    * @exception ClassNotFoundException when there is no such class
+    */
+   public Class loadClassWithout(DomainClassLoader loader, String className)
+           throws ClassNotFoundException
+   {
+      throw new ClassNotFoundException("NYI");
+   }
+
+   /**
+    * Get any wrapping classloader for the passed classloader
+    * 
+    * @param cl the wrapped classloader
+    * @return the wrapping classloader or null if not wrapped
+    */
+   public DomainClassLoader getWrappingClassLoader(DomainClassLoader cl)
+   {
+      synchronized (classLoaders)
+      {
+         return (DomainClassLoader) nonUCLClassLoader.get(cl);
+      }
+   }
+   
+   /** Add a class loader to the repository.
+    */
+   public void addClassLoader(DomainClassLoader loader)
+   {
+      // if you come to us as UCL we send you straight to the orbit
+      if (loader instanceof DomainClassLoader)
+         addDomainClassLoader((DomainClassLoader) loader);
+      else if (loader instanceof URLClassLoader)
+      {
+         addURLClassLoader((URLClassLoader) loader);
+      }
+      else
+      {
+         log.warn("Tried to add non-URLClassLoader.  Ignored");
+      } // end of else
+   }
+
+   public boolean addClassLoaderURL(DomainClassLoader cl, URL url)
+   {
+      DomainClassLoader ucl = (DomainClassLoader) cl;
+      boolean added = false;
+      synchronized (classLoaders)
+      {
+         // Strip any query parameter
+         String query = url.getQuery();
+         if (query != null)
+         {
+            String ext = url.toExternalForm();
+            String ext2 = ext.substring(0, ext.length() - query.length() - 1);
+            try
+            {
+               url = new URL(ext2);
+            }
+            catch (MalformedURLException e)
+            {
+               log.warn("Failed to strip query from: " + url, e);
+            }
+         }
+
+         // See if the URL is associated with a class loader
+         if (classLoaderURLs.contains(url) == false)
+         {
+            updatePackageMap(ucl, url);
+            classLoaderURLs.add(url);
+            added = true;
+            // Check for a dynamic URL
+            if (query != null && query.indexOf("dynamic=true") >= 0)
+               dynamicClassLoaders.add(ucl);
+         }
+      }
+      return added;
+   }
+   
+   /** Add a UCL to the repository.
+    * This sychronizes on classLoaders.
+    * @param cl
+    */
+   private void addDomainClassLoader(DomainClassLoader cl)
+   {
+      cl.setDomain(this);
+      // See if this URL already exists
+      URL url = cl.getURL();
+      boolean added = false;
+      synchronized (classLoaders)
+      {
+         boolean exists = false;
+         if (cl instanceof UnifiedClassLoader)
+            exists = classLoaderURLs.contains(url);
+         // If already present will not be added
+         if (!exists)
+         {
+            if (url != null)
+               classLoaderURLs.add(url);
+            added = classLoaders.add(cl);
+         }
+         if (added)
+         {
+            log.debug("Adding " + cl);
+            addedCount++;
+            cl.setAddedOrder(addedCount);
+            updatePackageMap(cl);
+         }
+         else
+         {
+            log.debug("Skipping duplicate " + cl);
+         }
+      }
+   }
+
+   private void addURLClassLoader(URLClassLoader loader)
+   {
+      URL[] urls = loader.getURLs();
+      int count = urls != null && urls.length > 0 ? urls.length : 0;
+      URL origURL = count > 0 ? urls[0] : null;
+      DomainClassLoaderUCLImpl ucl3 = new DomainClassLoaderUCLImpl(origURL, origURL, this);
+      addDomainClassLoader(ucl3);
+      synchronized (classLoaders)
+      {
+         nonUCLClassLoader.put(loader, ucl3);
+      }
+      for (int i = 1; i < count; i++)
+      {
+         this.addClassLoaderURL(ucl3, urls[i]);
+      }
+   }
+   
+   /** Walk through the class loader URL to see what packages it is capable
+    of handling
+    */
+   private void updatePackageMap(DomainClassLoader 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);
+      }
+   }
+
+   /** Walk through the new URL to update the packages the DomainClassLoader is
+    * capable of handling
+    */
+   private void updatePackageMap(DomainClassLoader cl, URL url)
+   {
+      try
+      {
+         String[] prevPkgNames = (String[]) loaderToPackagesMap.get(cl);
+         String[] pkgNames = ClassLoaderUtils.updatePackageMap(cl, packagesMap, url, prevPkgNames);
+         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);
+      }
+   }
+
+   /** Remove the class loader from the repository. This synchronizes on the
+    * this.classLoaders
+    */
+   public void removeClassLoader(DomainClassLoader loader)
+   {
+      ArrayList removeNotifications = new ArrayList();
+      DomainClassLoader cl = loader;
+      synchronized (classLoaders)
+      {
+         if ((loader instanceof DomainClassLoader) == false)
+         {
+            cl = (DomainClassLoader) nonUCLClassLoader.remove(loader);
+         }
+         if (cl instanceof DomainClassLoader)
+         {
+            DomainClassLoader ucl = (DomainClassLoader) cl;
+            if (getTranslator() != null)
+               getTranslator().unregisterClassLoader(ucl);
+            URL[] urls = ucl.getClasspath();
+            for (int u = 0; u < urls.length; u++)
+               classLoaderURLs.remove(urls[u]);
+         }
+         boolean dynamic = dynamicClassLoaders.remove(cl);
+         boolean removed = classLoaders.remove(cl);
+         log.debug("UnifiedLoaderRepository removed(" + removed + ") " + cl);
+
+         // Take care also of the cycling mapping for classes
+         HashSet loadedClasses = null;
+         boolean hasLoadedClasses = false;
+         synchronized (classes)
+         {
+            hasLoadedClasses = loaderToClassesMap.containsKey(cl);
+            if (hasLoadedClasses)
+               loadedClasses = (HashSet) loaderToClassesMap.remove(cl);
+            // This classloader has loaded at least one class
+            if (loadedClasses != null)
+            {
+               // Notify that classes are about to be removed
+               for (Iterator iter = loadedClasses.iterator(); iter.hasNext();)
+               {
+                  String className = (String) iter.next();
+                  Notification n = new Notification(CLASS_REMOVED, this,
+                          getNextSequenceNumber(), className);
+                  removeNotifications.add(n);
+               }
+
+               // Remove the classes from the global cache
+               for (Iterator i = loadedClasses.iterator(); i.hasNext();)
+               {
+                  String cls = (String) i.next();
+                  this.classes.remove(cls);
+               }
+            }
+         }
+
+         // Take care also of the cycling mapping for resources
+         synchronized (loaderToResourcesMap)
+         {
+            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
+         if (dynamic == false)
+         {
+            String[] pkgNames = (String[]) loaderToPackagesMap.remove(cl);
+            int length = pkgNames != null ? pkgNames.length : 0;
+            for (int p = 0; p < length; p++)
+            {
+               String pkgName = pkgNames[p];
+               Set pkgSet = (Set) packagesMap.get(pkgName);
+               if (pkgSet != null)
+               {
+                  pkgSet.remove(cl);
+                  if (pkgSet.isEmpty())
+                     packagesMap.remove(pkgName);
+               }
+            }
+         }
+         else
+         {
+            // A dynamic classloader could end up in any package set
+            loaderToPackagesMap.remove(cl);
+            for (Iterator i = packagesMap.entrySet().iterator(); i.hasNext();)
+            {
+               Map.Entry entry = (Map.Entry) i.next();
+               Set pkgSet = (Set) entry.getValue();
+               pkgSet.remove(cl);
+               if (pkgSet.isEmpty())
+                  i.remove();
+            }
+         }
+      }
+
+      // Send the class removal notfications outside of the synchronized block
+      for (int n = 0; n < removeNotifications.size(); n++)
+      {
+         Notification msg = (Notification) removeNotifications.get(n);
+         broadcaster.sendNotification(msg);
+      }
+
+      Notification msg = new Notification(CLASSLOADER_REMOVED, this, getNextSequenceNumber());
+      msg.setUserData(cl);
+      broadcaster.sendNotification(msg);
+   }
+
+   /**
+    * 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 LoaderRepositoryDomain registerClassLoader(DomainClassLoader ucl)
+   {
+      addClassLoader(ucl);
+      Notification msg = new Notification(CLASSLOADER_ADDED, this, getNextSequenceNumber());
+      msg.setUserData(ucl);
+      broadcaster.sendNotification(msg);
+
+      return this;
+   }
+
+   /**
+    * @jmx.managed-operation
+    */
+   public LoaderRepositoryDomain 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);
+   }
+
+   // MBeanRegistration
+   public ObjectName preRegister(MBeanServer server, ObjectName name)
+      throws Exception
+   {
+      return name;
+   }
+
+   public void postRegister(Boolean registrationDone)
+   {
+   }
+
+   public void preDeregister()
+      throws Exception
+   {
+   }
+
+   public void postDeregister()
+   {
+      log.debug("postDeregister, clearing all references");
+      classLoaders.clear();
+      dynamicClassLoaders.clear();
+      nonUCLClassLoader.clear();
+      classLoaderURLs.clear();
+      classes.clear();
+      loaderToClassesMap.clear();
+      loaderToResourcesMap.clear();
+      globalResources.clear();
+      packagesMap.clear();
+      loaderToPackagesMap.clear();
+   }
+
+   private synchronized long getNextSequenceNumber()
+   {
+      return sequenceNumber++;
+   }
+
+
+}

Added: branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCLMBean.java
===================================================================
--- branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCLMBean.java	2006-08-29 02:01:28 UTC (rev 56380)
+++ branches/MC_VDF_WORK/jmx/src/main/org/jboss/mx/loading/UnifiedLoaderRepositoryDCLMBean.java	2006-08-29 02:02:32 UTC (rev 56381)
@@ -0,0 +1,50 @@
+package org.jboss.mx.loading;
+
+import java.net.URL;
+import java.util.Set;
+
+import org.jboss.classloading.spi.DomainClassLoader;
+import org.jboss.util.loading.Translator;
+
+public interface UnifiedLoaderRepositoryDCLMBean
+{
+   public DomainClassLoader newClassLoader(final URL url, boolean addToRepository)
+   throws Exception;
+   public DomainClassLoader newClassLoader(final URL url, final URL origURL, boolean addToRepository)
+      throws Exception;
+   
+   public void removeClassLoader(DomainClassLoader cl);
+   
+   public LoaderRepositoryDomain registerClassLoader(DomainClassLoader ucl);
+   
+   public LoaderRepositoryDomain getInstance();
+   
+   public URL[] getURLs();
+   
+   // Aspect stuff
+   public Translator getTranslator();
+   public void setTranslator(Translator t);
+
+   /** Called by LoadMgr to obtain all class loaders for the given className
+    *@return LinkedList<UnifiedClassLoader3>, may be null
+    */
+   public Set getPackageClassLoaders(String className);
+
+   /** A utility method that iterates over all repository class loader and
+    * display the class information for every UCL that contains the given
+    * className
+    */
+   public String displayClassInfo(String className);
+
+   /** Get the number of classes loaded into the ULR cache.
+    * @return the classes cache size.
+    */
+   public int getCacheSize();
+   /** Get the number of UnifiedClassLoader3s (UCLs) in the ULR
+    * @return the number of UCLs in the ULR
+    */
+   public int getClassLoadersSize();
+   /** Flush the ULR classes cache
+    */
+   public void flush();
+}




More information about the jboss-cvs-commits mailing list