[jboss-cvs] JBossAS SVN: r96496 - in projects/jboss-cl/trunk/classloader/src: main/java/org/jboss/classloader/spi/base and 6 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Nov 18 11:54:15 EST 2009


Author: adrian at jboss.org
Date: 2009-11-18 11:54:13 -0500 (Wed, 18 Nov 2009)
New Revision: 96496

Added:
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundEvent.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundHandler.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEvent.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEventHandler.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundEvent.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundHandler.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/ClassLoaderNotificationsTestSuite.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/support/
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/support/a/
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/support/a/A.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassFoundHandlerUnitTestCase.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassLoaderEventHandlerUnitTestCase.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassNotFoundHandlerUnitTestCase.java
Modified:
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderDomain.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderPolicy.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderSystem.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoader.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderDomain.java
   projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderPolicy.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/ClassLoaderAllTestSuite.java
   projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/domain/test/CustomParentLoaderUnitTestCase.java
Log:
[JBCL-127] [JBCL-128] - Notifications and handlers for ClassLoader create/destroy, ClassNotFound and ClassFound

Added: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundEvent.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundEvent.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundEvent.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,87 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.classloader.spi;
+
+import java.util.EventObject;
+
+/**
+ * ClassFoundEvent.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClassFoundEvent extends EventObject
+{
+   /** The serialVersionUID */
+   private static final long serialVersionUID = -8258925782380851534L;
+
+   /** The class */
+   private Class<?> clazz;
+   
+   /**
+    * Create a new ClassFoundEvent.
+    * 
+    * @param classLoader classLoader
+    * @param clazz the class
+    */
+   public ClassFoundEvent(ClassLoader classLoader, Class<?> clazz)
+   {
+      super(classLoader);
+      this.clazz = clazz;
+   }
+
+   /**
+    * Get the className.
+    * 
+    * @return the className.
+    */
+   public String getClassName()
+   {
+      return clazz.getName();
+   }
+
+   /**
+    * Get the class.
+    * 
+    * @return the class.
+    */
+   public Class<?> getClazz()
+   {
+      return clazz;
+   }
+
+   /**
+    * Get the classLoader.
+    * 
+    * @return the classLoader
+    */
+   public ClassLoader getClassLoader()
+   {
+      return (ClassLoader) getSource();
+   }
+
+   @Override
+   public String toString()
+   {
+      return getClass().getSimpleName() + "[classLoader=" + getClassLoader() + " class=" + getClassName() + "]";
+   }
+}

Added: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundHandler.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundHandler.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassFoundHandler.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,38 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.classloader.spi;
+
+/**
+ * ClassFoundHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public interface ClassFoundHandler
+{
+   /**
+    * Fired when a class is found
+    * 
+    * @param event the event
+    */
+   void classFound(ClassFoundEvent event);
+}

Modified: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderDomain.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderDomain.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderDomain.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -33,6 +33,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.management.MBeanRegistration;
 import javax.management.MBeanServer;
@@ -41,6 +42,7 @@
 import org.jboss.classloader.plugins.ClassLoaderUtils;
 import org.jboss.classloader.plugins.loader.ClassLoaderToLoaderAdapter;
 import org.jboss.classloader.spi.base.BaseClassLoaderDomain;
+import org.jboss.classloader.spi.base.BaseClassLoaderSource;
 import org.jboss.classloader.spi.filter.ClassFilter;
 import org.jboss.classloading.spi.RealClassLoader;
 import org.jboss.logging.Logger;
@@ -51,7 +53,7 @@
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @version $Revision: 1.1 $
  */
-public class ClassLoaderDomain extends BaseClassLoaderDomain implements Loader, ClassLoaderDomainMBean, MBeanRegistration
+public class ClassLoaderDomain extends BaseClassLoaderDomain implements Loader, ClassLoaderDomainMBean, MBeanRegistration, ClassNotFoundHandler, ClassFoundHandler
 {
    /** The log */
    private static final Logger log = Logger.getLogger(ClassLoaderDomain.class);
@@ -73,6 +75,15 @@
    
    /** Whether to use load class for the parent */
    private boolean useLoadClassForParent = false;
+
+   /** The class not found handlers */
+   private List<ClassNotFoundHandler> classNotFoundHandlers;
+
+   /** The class found handlers */
+   private List<ClassFoundHandler> classFoundHandlers;
+
+   /** The class loader event handlers */
+   private List<ClassLoaderEventHandler> classLoaderEventHandlers;
    
    /**
     * Create a new ClassLoaderDomain with the {@link ParentPolicy#BEFORE} loading rules.
@@ -287,7 +298,228 @@
       else
          builder.append(getParentClassLoader());
    }
+   
+   /**
+    * Add a ClassNotFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassNotFoundHandler(ClassNotFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classNotFoundHandlers == null)
+         classNotFoundHandlers = new CopyOnWriteArrayList<ClassNotFoundHandler>();
+      
+      classNotFoundHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassNotFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassNotFoundHandler(ClassNotFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classNotFoundHandlers == null)
+         return;
+      classNotFoundHandlers.remove(handler);
+   }
 
+   public boolean classNotFound(ClassNotFoundEvent event)
+   {
+      String className = event.getClassName();
+
+      ClassNotFoundHandler parent = null;
+      Loader parentLoader = getParent();
+      if (parentLoader instanceof ClassNotFoundHandler)
+         parent = (ClassNotFoundHandler) parentLoader;
+
+      ClassLoaderPolicy parentPolicy = getClassLoaderPolicy(parentLoader);
+      if (parentPolicy != null)
+         parent = parentPolicy;
+      
+      boolean parentResult = false;
+      if (parent != null)
+         parentResult = parent.classNotFound(event);
+
+      // Try the parent before
+      if (parentResult && getParentPolicy().getBeforeFilter().matchesClassName(className))
+         return true;
+      
+      if (classNotFoundHandlers != null && classNotFoundHandlers.isEmpty() == false)
+      {
+         for (ClassNotFoundHandler handler : classNotFoundHandlers)
+         {
+            try
+            {
+               if (handler.classNotFound(event))
+                  return true;
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classNotFoundHandler: " + handler, t);
+            }
+         }
+      }
+
+      // Try the parent after
+      if (parentResult && getParentPolicy().getAfterFilter().matchesClassName(className))
+         return true;
+      
+      ClassLoaderSystem system = (ClassLoaderSystem) getClassLoaderSystem();
+      if (system == null)
+         return false;
+      return system.classNotFound(event);
+   }
+   
+   /**
+    * Add a ClassFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassFoundHandler(ClassFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classFoundHandlers == null)
+         classFoundHandlers = new CopyOnWriteArrayList<ClassFoundHandler>();
+      
+      classFoundHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassFoundHandler(ClassFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classFoundHandlers == null)
+         return;
+      classFoundHandlers.remove(handler);
+   }
+
+   public void classFound(ClassFoundEvent event)
+   {
+      ClassFoundHandler parent = null;
+      Loader parentLoader = getParent();
+      if (parentLoader instanceof ClassFoundHandler)
+         parent = (ClassFoundHandler) parentLoader;
+
+      ClassLoaderPolicy parentPolicy = getClassLoaderPolicy(parentLoader);
+      if (parentPolicy != null)
+         parent = parentPolicy;
+      
+      if (parent != null)
+         parent.classFound(event);
+      
+      if (classFoundHandlers != null && classFoundHandlers.isEmpty() == false)
+      {
+         for (ClassFoundHandler handler : classFoundHandlers)
+         {
+            try
+            {
+               handler.classFound(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classFoundHandler: " + handler, t);
+            }
+         }
+      }
+      
+      ClassLoaderSystem system = (ClassLoaderSystem) getClassLoaderSystem();
+      if (system == null)
+         return;
+      system.classFound(event);
+   }
+   
+   /**
+    * Add a ClassLoaderEventHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassLoaderEventHandler(ClassLoaderEventHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classLoaderEventHandlers == null)
+         classLoaderEventHandlers = new CopyOnWriteArrayList<ClassLoaderEventHandler>();
+      
+      classLoaderEventHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassLoaderEventHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassLoaderEventHandler(ClassLoaderEventHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classLoaderEventHandlers == null)
+         return;
+      classLoaderEventHandlers.remove(handler);
+   }
+
+   private void fireRegisterClassLoader(ClassLoaderEvent event)
+   {
+      if (classLoaderEventHandlers != null && classLoaderEventHandlers.isEmpty() == false)
+      {
+         for (ClassLoaderEventHandler handler : classLoaderEventHandlers)
+         {
+            try
+            {
+               handler.fireRegisterClassLoader(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classLoaderEventHandler: " + handler, t);
+            }
+         }
+      }
+      
+      ClassLoaderSystem system = (ClassLoaderSystem) getClassLoaderSystem();
+      if (system == null)
+         return;
+      system.fireRegisterClassLoader(event);
+   }
+
+   private void fireUnregisterClassLoader(ClassLoaderEvent event)
+   {
+      if (classLoaderEventHandlers != null && classLoaderEventHandlers.isEmpty() == false)
+      {
+         for (ClassLoaderEventHandler handler : classLoaderEventHandlers)
+         {
+            try
+            {
+               handler.fireUnregisterClassLoader(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classLoaderEventHandler: " + handler, t);
+            }
+         }
+      }
+      
+      ClassLoaderSystem system = (ClassLoaderSystem) getClassLoaderSystem();
+      if (system == null)
+         return;
+      system.fireUnregisterClassLoader(event);
+   }
+
    @Override
    public String toString()
    {
@@ -686,7 +918,8 @@
       }
       finally
       {
-         setUseLoadClassForParent(parent instanceof ClassLoaderDomain == false);
+         if ((parent instanceof ClassLoaderDomain == false) && (parent instanceof BaseClassLoaderSource == false))
+            setUseLoadClassForParent(true);
       }
    }
 
@@ -728,11 +961,13 @@
    protected void afterRegisterClassLoader(ClassLoader classLoader, ClassLoaderPolicy policy)
    {
       registerClassLoaderMBean(classLoader);
+      fireRegisterClassLoader(new ClassLoaderEvent(this, classLoader));
    }
 
    @Override
    protected void beforeUnregisterClassLoader(ClassLoader classLoader, ClassLoaderPolicy policy)
    {
+      fireUnregisterClassLoader(new ClassLoaderEvent(this, classLoader));
       unregisterClassLoaderMBean(classLoader);
    }
 

Added: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEvent.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEvent.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEvent.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,77 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.classloader.spi;
+
+import java.util.EventObject;
+
+/**
+ * ClassLoaderEvent.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClassLoaderEvent extends EventObject
+{
+   /** The serialVersionUID */
+   private static final long serialVersionUID = -5874702798336257018L;
+
+   /** The classLoader */
+   private ClassLoader classLoader;
+   
+   /**
+    * Create a new ClassLoaderEvent.
+    *
+    * @param classLoaderDomain the classLoaderDomain
+    * @param classLoader classLoader
+    */
+   public ClassLoaderEvent(ClassLoaderDomain classLoaderDomain, ClassLoader classLoader)
+   {
+      super(classLoaderDomain);
+      this.classLoader = classLoader;
+   }
+
+   /**
+    * Get the classLoader.
+    * 
+    * @return the classLoader
+    */
+   public ClassLoader getClassLoader()
+   {
+      return classLoader;
+   }
+
+   /**
+    * Get the classLoaderDomain.
+    * 
+    * @return the classLoaderDomain
+    */
+   public ClassLoaderDomain getClassLoaderDomain()
+   {
+      return (ClassLoaderDomain) getSource();
+   }
+
+   @Override
+   public String toString()
+   {
+      return getClass().getSimpleName() + "[classLoaderDomain=" + getClassLoaderDomain() + " classLoader=" + getClassLoader() + "]";
+   }
+}

Added: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEventHandler.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEventHandler.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderEventHandler.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,45 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.classloader.spi;
+
+/**
+ * ClassLoaderEventHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public interface ClassLoaderEventHandler
+{
+   /**
+    * Fired when a classLoader is registered
+    * 
+    * @param event the classloader event
+    */
+   void fireRegisterClassLoader(ClassLoaderEvent event);
+
+   /**
+    * Fired when a classLoader is registered
+    * 
+    * @param event the classloader event
+    */
+   void fireUnregisterClassLoader(ClassLoaderEvent event);
+}

Modified: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderPolicy.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderPolicy.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderPolicy.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -31,6 +31,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
@@ -48,11 +49,17 @@
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @version $Revision: 1.1 $
  */
-public abstract class ClassLoaderPolicy extends BaseClassLoaderPolicy
+public abstract class ClassLoaderPolicy extends BaseClassLoaderPolicy implements ClassNotFoundHandler, ClassFoundHandler
 {
    /** The log */
    private static final Logger log = Logger.getLogger(ClassLoaderPolicy.class);
 
+   /** The class not found handlers */
+   private List<ClassNotFoundHandler> classNotFoundHandlers;
+
+   /** The class found handlers */
+   private List<ClassFoundHandler> classFoundHandlers;
+   
    /**
     * Get the delegate loader for exported stuff<p>
     *
@@ -142,6 +149,7 @@
     * @param path the path
     * @return the url or null if not found
     */
+   // FindBugs: The Set doesn't use equals/hashCode
    public abstract URL getResource(String path);
 
    /**
@@ -176,7 +184,6 @@
     * @param urls the list of urls to add to
     * @throws IOException for any error
     */
-   // FindBugs: The Set doesn't use equals/hashCode
    public abstract void getResources(String name, Set<URL> urls) throws IOException;
    
    /**
@@ -237,7 +244,116 @@
          return getSystemClassLoader();
       return null;
    }
+   
+   /**
+    * Add a ClassNotFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassNotFoundHandler(ClassNotFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classNotFoundHandlers == null)
+         classNotFoundHandlers = new CopyOnWriteArrayList<ClassNotFoundHandler>();
+      
+      classNotFoundHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassNotFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassNotFoundHandler(ClassNotFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classNotFoundHandlers == null)
+         return;
+      classNotFoundHandlers.remove(handler);
+   }
 
+   public boolean classNotFound(ClassNotFoundEvent event)
+   {
+      if (classNotFoundHandlers != null && classNotFoundHandlers.isEmpty() == false)
+      {
+         for (ClassNotFoundHandler handler : classNotFoundHandlers)
+         {
+            try
+            {
+               if (handler.classNotFound(event))
+                  return true;
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classNotFoundHandler: " + handler, t);
+            }
+         }
+      }
+      
+      ClassLoaderDomain domain = getDomain();
+      if (domain == null)
+         return false;
+      return domain.classNotFound(event);
+   }
+   
+   /**
+    * Add a ClassFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassFoundHandler(ClassFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classFoundHandlers == null)
+         classFoundHandlers = new CopyOnWriteArrayList<ClassFoundHandler>();
+      
+      classFoundHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassFoundHandler(ClassFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classFoundHandlers == null)
+         return;
+      classFoundHandlers.remove(handler);
+   }
+
+   public void classFound(ClassFoundEvent event)
+   {
+      if (classFoundHandlers != null && classFoundHandlers.isEmpty() == false)
+      {
+         for (ClassFoundHandler handler : classFoundHandlers)
+         {
+            try
+            {
+               handler.classFound(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classFoundHandler: " + handler, t);
+            }
+         }
+      }
+      
+      ClassLoaderDomain domain = getDomain();
+      if (domain == null)
+         return;
+      domain.classFound(event);
+   }
+
    @Override
    public ObjectName getObjectName()
    {

Modified: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderSystem.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderSystem.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassLoaderSystem.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -23,6 +23,7 @@
 
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -30,7 +31,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Collections;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.management.MBeanRegistration;
 import javax.management.MBeanServer;
@@ -50,7 +51,7 @@
  * @author <a href="ales.justin at jboss.com">Ales Justin</a>
  * @version $Revision: 1.1 $
  */
-public abstract class ClassLoaderSystem extends BaseClassLoaderSystem implements ClassLoaderSystemMBean, MBeanRegistration
+public abstract class ClassLoaderSystem extends BaseClassLoaderSystem implements ClassLoaderSystemMBean, MBeanRegistration, ClassNotFoundHandler, ClassFoundHandler, ClassLoaderEventHandler
 {
    /** The log */
    private static final Logger log = Logger.getLogger(ClassLoaderSystem.class);
@@ -78,6 +79,15 @@
    
    /** The object name */
    private ObjectName objectName;
+
+   /** The class not found handlers */
+   private List<ClassNotFoundHandler> classNotFoundHandlers;
+
+   /** The class found handlers */
+   private List<ClassFoundHandler> classFoundHandlers;
+
+   /** The class loader event handlers */
+   private List<ClassLoaderEventHandler> classLoaderEventHandlers;
    
    /**
     * Get the classloading system instance
@@ -182,6 +192,7 @@
    public ClassLoaderDomain createAndRegisterDomain(String name, ParentPolicy parentPolicy, Loader parent)
    {
       ClassLoaderDomain result = createDomain(name);
+      assert result != null : "createDomain(" + name + ") returned null";
       result.setParentPolicy(parentPolicy);
       result.setParent(parent);
       registerDomain(result);
@@ -520,7 +531,7 @@
     * @deprecated use translator list
     */
    @Deprecated
-   public Translator getTranslator()
+   public synchronized Translator getTranslator()
    {
       if (translators == null || translators.isEmpty())
          return null;
@@ -535,7 +546,7 @@
     * @deprecated use translator list
     */
    @Deprecated
-   public void setTranslator(Translator translator)
+   public synchronized void setTranslator(Translator translator)
    {
       log.debug(this + " set translator to " + translator);
 
@@ -548,7 +559,7 @@
    @Override
    protected byte[] transform(ClassLoader classLoader, String className, byte[] byteCode, ProtectionDomain protectionDomain) throws Exception
    {
-      byte[] result = TranslatorUtils.applyTranslatorsOnTransform(translators, classLoader, className, byteCode, protectionDomain);
+      byte[] result = TranslatorUtils.applyTranslatorsOnTransform(getTranslators(), classLoader, className, byteCode, protectionDomain);
       return super.transform(classLoader, className, result, protectionDomain);
    }
 
@@ -557,7 +568,7 @@
    {
       try
       {
-         TranslatorUtils.applyTranslatorsAtUnregister(translators, classLoader);
+         TranslatorUtils.applyTranslatorsAtUnregister(getTranslators(), classLoader);
       }
       catch (Throwable t)
       {
@@ -685,7 +696,174 @@
          log.warn("Error unregistering domain: " + domain, e);
       }
    }
+   
+   /**
+    * Add a ClassNotFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassNotFoundHandler(ClassNotFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classNotFoundHandlers == null)
+         classNotFoundHandlers = new CopyOnWriteArrayList<ClassNotFoundHandler>();
+      
+      classNotFoundHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassNotFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassNotFoundHandler(ClassNotFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classNotFoundHandlers == null)
+         return;
+      classNotFoundHandlers.remove(handler);
+   }
 
+   public boolean classNotFound(ClassNotFoundEvent event)
+   {
+      if (classNotFoundHandlers != null && classNotFoundHandlers.isEmpty() == false)
+      {
+         for (ClassNotFoundHandler handler : classNotFoundHandlers)
+         {
+            try
+            {
+               if (handler.classNotFound(event))
+                  return true;
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classNotFoundHandler: " + handler, t);
+            }
+         }
+      }
+      return false;
+   }
+   
+   /**
+    * Add a ClassFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassFoundHandler(ClassFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classFoundHandlers == null)
+         classFoundHandlers = new CopyOnWriteArrayList<ClassFoundHandler>();
+      
+      classFoundHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassFoundHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassFoundHandler(ClassFoundHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classFoundHandlers == null)
+         return;
+      classFoundHandlers.remove(handler);
+   }
+
+   public void classFound(ClassFoundEvent event)
+   {
+      if (classFoundHandlers != null && classFoundHandlers.isEmpty() == false)
+      {
+         for (ClassFoundHandler handler : classFoundHandlers)
+         {
+            try
+            {
+               handler.classFound(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classFoundHandler: " + handler, t);
+            }
+         }
+      }
+   }
+   
+   /**
+    * Add a ClassLoaderEventHandler
+    * 
+    * @param handler the handler
+    */
+   public void addClassLoaderEventHandler(ClassLoaderEventHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classLoaderEventHandlers == null)
+         classLoaderEventHandlers = new CopyOnWriteArrayList<ClassLoaderEventHandler>();
+      
+      classLoaderEventHandlers.add(handler);
+   }
+   
+   /**
+    * Remove a ClassLoaderEventHandler
+    * 
+    * @param handler the handler
+    */
+   public void removeClassLoaderEventHandler(ClassLoaderEventHandler handler)
+   {
+      if (handler == null)
+         throw new IllegalArgumentException("Null handler");
+      
+      if (classLoaderEventHandlers == null)
+         return;
+      classLoaderEventHandlers.remove(handler);
+   }
+
+   public void fireRegisterClassLoader(ClassLoaderEvent event)
+   {
+      if (classLoaderEventHandlers != null && classLoaderEventHandlers.isEmpty() == false)
+      {
+         for (ClassLoaderEventHandler handler : classLoaderEventHandlers)
+         {
+            try
+            {
+               handler.fireRegisterClassLoader(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classLoaderEventHandler: " + handler, t);
+            }
+         }
+      }
+   }
+
+   public void fireUnregisterClassLoader(ClassLoaderEvent event)
+   {
+      if (classLoaderEventHandlers != null && classLoaderEventHandlers.isEmpty() == false)
+      {
+         for (ClassLoaderEventHandler handler : classLoaderEventHandlers)
+         {
+            try
+            {
+               handler.fireUnregisterClassLoader(event);
+            }
+            catch (Throwable t)
+            {
+               log.warn("Error invoking classLoaderEventHandler: " + handler, t);
+            }
+         }
+      }
+   }
+
    @Override
    protected void toLongString(StringBuilder builder)
    {

Added: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundEvent.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundEvent.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundEvent.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,77 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.classloader.spi;
+
+import java.util.EventObject;
+
+/**
+ * ClassNotFoundEvent.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClassNotFoundEvent extends EventObject
+{
+   /** The serialVersionUID */
+   private static final long serialVersionUID = 7445562838711417089L;
+
+   /** The class name */
+   private String className;
+   
+   /**
+    * Create a new ClassNotFoundEvent.
+    * 
+    * @param classLoader the classLoader
+    * @param className the class name
+    */
+   public ClassNotFoundEvent(ClassLoader classLoader, String className)
+   {
+      super(classLoader);
+      this.className = className;
+   }
+
+   /**
+    * Get the className.
+    * 
+    * @return the className.
+    */
+   public String getClassName()
+   {
+      return className;
+   }
+
+   /**
+    * Get the classLoader.
+    * 
+    * @return the classLoader
+    */
+   public ClassLoader getClassLoader()
+   {
+      return (ClassLoader) getSource();
+   }
+
+   @Override
+   public String toString()
+   {
+      return getClass().getSimpleName() + "[classLoader=" + getClassLoader() + " class=" + getClassName() + "]";
+   }
+}

Added: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundHandler.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundHandler.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/ClassNotFoundHandler.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,39 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.classloader.spi;
+
+/**
+ * ClassNotFoundHandler.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public interface ClassNotFoundHandler
+{
+   /**
+    * Fired when a class is not found
+    * 
+    * @param event the event
+    * @return true when the a retry of the classloading should be tried
+    */
+   boolean classNotFound(ClassNotFoundEvent event);
+}

Modified: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoader.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoader.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoader.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -46,8 +46,10 @@
 import javax.management.ObjectName;
 
 import org.jboss.classloader.plugins.ClassLoaderUtils;
+import org.jboss.classloader.spi.ClassFoundEvent;
 import org.jboss.classloader.spi.ClassLoaderDomain;
 import org.jboss.classloader.spi.ClassLoaderPolicy;
+import org.jboss.classloader.spi.ClassNotFoundEvent;
 import org.jboss.classloader.spi.DelegateLoader;
 import org.jboss.classloader.spi.Loader;
 import org.jboss.classloader.spi.PackageInformation;
@@ -57,39 +59,39 @@
 
 /**
  * BaseClassLoader.
- * 
+ *
  * @author <a href="adrian at jboss.com">Adrian Brock</a>
  * @version $Revision: 1.1 $
  */
-public class BaseClassLoader extends SecureClassLoader implements BaseClassLoaderMBean, RealClassLoader 
+public class BaseClassLoader extends SecureClassLoader implements BaseClassLoaderMBean, RealClassLoader
 {
    /** The log */
    private static final Logger log = Logger.getLogger(BaseClassLoader.class);
 
    /** The lock object */
    private ReentrantLock lock = new ReentrantLock(true);
-   
+
    /** The policy for this classloader */
    private ClassLoaderPolicy policy;
-   
+
    /** Our Loader front end */
    private DelegateLoader loader;
-   
+
    /** The loaded classes */
    private Map<String, String> loadedClasses = new ConcurrentHashMap<String, String>();
-   
+
    /** Our resource cache */
    private Map<String, URL> resourceCache;
-   
+
    /** Our black list */
    private Map<String, String> blackList;
-   
+
    /**
     * Create a new ClassLoader with no parent.
-    * 
+    *
     * @param policy the policy
-    * @throws IllegalArgumentException for a null policy 
-    * @throws IllegalStateException if the policy is already associated with a classloader 
+    * @throws IllegalArgumentException for a null policy
+    * @throws IllegalStateException if the policy is already associated with a classloader
     */
    public BaseClassLoader(ClassLoaderPolicy policy)
    {
@@ -108,7 +110,7 @@
 
       if (basePolicy.isBlackListable())
          blackList = new ConcurrentHashMap<String, String>();
-      
+
       log.debug("Created " + this + " with policy " + policy.toLongString());
    }
 
@@ -116,7 +118,7 @@
    {
       return policy.getObjectName();
    }
-   
+
    public ObjectName getClassLoaderDomain()
    {
       BaseClassLoaderPolicy basePolicy = policy;
@@ -128,7 +130,7 @@
    {
       return policy.getName();
    }
-   
+
    public boolean isBlackListable()
    {
       BaseClassLoaderPolicy basePolicy = policy;
@@ -173,7 +175,7 @@
       }
       return result;
    }
-   
+
    public String listPolicyDetails()
    {
       return policy.toLongString();
@@ -184,18 +186,18 @@
       final Class<?> clazz = loadClass(name);
       if (clazz == null)
          return null;
-      
+
       ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>()
       {
          public ClassLoader run()
          {
-            return clazz.getClassLoader(); 
+            return clazz.getClassLoader();
          }
       });
-      
+
       if (cl != null && cl instanceof RealClassLoader)
          return ((RealClassLoader) cl).getObjectName();
-      
+
       return null;
    }
 
@@ -223,7 +225,7 @@
 
    /**
     * Get the policy.
-    * 
+    *
     * @return the policy.
     */
    ClassLoaderPolicy getPolicy()
@@ -233,7 +235,7 @@
 
    /**
     * Get the loader.
-    * 
+    *
     * @return the loader.
     */
    DelegateLoader getLoader()
@@ -250,12 +252,12 @@
 
       if (name == null)
          return null;
-      
+
       // Did we already load this package?
       Package result = super.getPackage(name);
       if (result != null && trace)
          log.trace(this + " already loaded package " + name + " " + result.getName());
-      
+
       // Not already loaded use the domain
       if (result == null)
       {
@@ -267,14 +269,14 @@
             log.trace(this + " getPackage " + name + " domain=" + domain);
          result = domain.getPackage(this, name);
       }
-      
+
       // Still not found
       if (result == null)
       {
          if (trace)
             log.trace(this + " package not found " + name);
       }
-      
+
       return result;
    }
 
@@ -296,7 +298,7 @@
 
    /**
     * Get a package locally
-    * 
+    *
     * @param name the package name
     * @return the package
     */
@@ -307,7 +309,7 @@
 
    /**
     * Get the packages locally
-    * 
+    *
     * @param packages the packages
     */
    void getPackagesLocally(Set<Package> packages)
@@ -316,10 +318,10 @@
       for (Package pkg : pkgs)
          packages.add(pkg);
    }
-   
+
    /**
     * Check to see if the class is already loaded
-    * 
+    *
     * @param name the name of the class
     * @param trace whether trace is enabled
     * @return the class is if it is already loaded, null otherwise
@@ -347,10 +349,10 @@
          log.trace(this + " already loaded class " + ClassLoaderUtils.classToString(result));
       return result;
    }
-   
+
    /**
     * Check the cache and blacklist
-    * 
+    *
     * @param name the name of the class
     * @param failIfBlackListed <code>true</code> if a blacklisted class should
     *                          result in ClassNotFoundException; <code>false</code>
@@ -367,12 +369,12 @@
       if (domain == null)
          return null;
 
-      return domain.checkClassCacheAndBlackList(this, name, null, basePolicy.isImportAll(), failIfBlackListed);
+      return domain.checkClassCacheAndBlackList(this, name, null, basePolicy.isImportAll(), false);
    }
 
    /**
     * Find the classloader for a class but don't load the class
-    * 
+    *
     * @param className the class name
     * @return the classloader
     * @throws ClassNotFoundException if the class is not found
@@ -392,11 +394,11 @@
 
       ClassLoaderUtils.checkClassName(className);
       String path = ClassLoaderUtils.classNameToPath(className);
-      
+
       Loader loader = domain.findLoader(this, path, basePolicy.isImportAll(), true);
       if (loader == null)
          throw new ClassNotFoundException("Class " + className + " not found from " + this);
-      
+
       // This is a bit ugly but we can't abstract this behind an interface because
       // that would make the methods public
       if (loader instanceof BaseClassLoaderSource)
@@ -412,10 +414,10 @@
       boolean trace = log.isTraceEnabled();
       if (trace)
          log.trace(this + " loadClass " + name + " resolve=" + resolve);
-      
+
       // Validate the class name makes sense
       ClassLoaderUtils.checkClassName(name);
-      
+
       // Did we already load this class?
       Class<?> result = isLoadedClass(name, trace);
 
@@ -434,21 +436,72 @@
       result = checkCacheAndBlackList(name, false, trace);
       if (result != null)
          return result;
+
+      // Try to load the class
+      ClassNotFoundException exception = null;
+      try
+      {
+         result = doLoadClass(name, resolve, trace);
+      }
+      catch (ClassNotFoundException e)
+      {
+         exception = e;
+      }
       
+      // If we failed, try any class not found handlers and retry if one says it is resolved
+      if (result == null)
+      {
+         ClassLoaderPolicy policy = getPolicy();
+         if (policy != null && policy.classNotFound(new ClassNotFoundEvent(this, name)))
+         {
+            try
+            {
+               result = doLoadClass(name, resolve, trace);
+            }
+            catch (ClassNotFoundException e)
+            {
+               exception = e;
+            }
+         }
+      }
+      
+      if (result == null)
+      {
+         if (trace)
+            log.trace(this + " class not found " + name);
+         if (exception != null)
+            throw exception;
+         throw new ClassNotFoundException(name + " from " + toString());
+      }
+      return result;
+   }
+
+   /**
+    * Do the load class
+    * 
+    * @param name the name
+    * @param resolve whether to resolve
+    * @param trace whether trace is enabled
+    * @return the class or null if not found
+    * @throws ClassNotFoundException if a problem is raised
+    */
+   protected Class<?> doLoadClass(String name, boolean resolve, boolean trace) throws ClassNotFoundException
+   {
+      Class<?> result = null;
+      
       synchronized (this)
       {
+         // JBCL-114: did we lose the race to the synchronized?
+         result = isLoadedClass(name, trace);
+         
          // Not already loaded use the domain
          if (result == null)
             result = loadClassFromDomain(name, trace);
-         
+
          // Still not found
          if (result == null)
-         {
-            if (trace)
-               log.trace(this + " class not found " + name);
-            throw new ClassNotFoundException(name + " from " + toLongString());
-         }
-         
+            return null;
+
          // Link the class if requested
          if (resolve)
          {
@@ -456,7 +509,7 @@
                log.trace(this + " resolveClass " + ClassLoaderUtils.classToString(result));
             resolveClass(result);
          }
-         
+
          return result;
       }
    }
@@ -497,10 +550,10 @@
          domain.getResources(this, name, resourceURLs);
       return resourceURLs;
    }
-   
+
    /**
     * Try to load the class locally
-    * 
+    *
     * @param name the class name
     * @return the class
     */
@@ -511,7 +564,7 @@
 
    /**
     * Try to load the class locally
-    * 
+    *
     * @param name the class name
     * @param trace whether trace is enabled
     * @return the class if found
@@ -528,7 +581,7 @@
 
       // Look for the resource
       final String resourcePath = ClassLoaderUtils.classNameToPath(name);
-      
+
       result = AccessController.doPrivileged(new PrivilegedAction<Class<?>>()
       {
          public Class<?> run()
@@ -543,7 +596,7 @@
 
             // Load the bytecode
             byte[] byteCode = ClassLoaderUtils.loadByteCode(name, is);
-            
+
             // Let the policy do things before we define the class
             BaseClassLoaderPolicy basePolicy = policy;
             ProtectionDomain protectionDomain = basePolicy.getProtectionDomain(name, resourcePath);
@@ -557,7 +610,7 @@
             {
                throw new RuntimeException("Unexpected error transforming class " + name, t);
             }
-            
+
             // Create the package if necessary
             URL codeSourceURL = null;
             if (protectionDomain != null)
@@ -567,7 +620,7 @@
                   codeSourceURL = codeSource.getLocation();
             }
             definePackage(name, codeSourceURL);
-            
+
             // Finally we can define the class
             Class<?> result;
             if (protectionDomain != null)
@@ -579,15 +632,16 @@
             return result;
          }
       }, policy.getAccessControlContext());
-      
+
       loadedClasses.put(name, name);
-      
+      policy.classFound(new ClassFoundEvent(this, result));
+
       return result;
    }
 
    /**
     * Try to find the resource locally
-    * 
+    *
     * @param name the resource name
     * @return the url if found
     */
@@ -598,7 +652,7 @@
 
    /**
     * Try to find the resource locally
-    * 
+    *
     * @param name the resource name
     * @param trace whether trace is enabled
     * @return the URL if found
@@ -619,7 +673,7 @@
             return url;
          }
       }
-      
+
       // Is this resource blacklisted?
       if (blackList != null && blackList.containsKey(name))
       {
@@ -627,7 +681,7 @@
             log.trace(this + " resource is blacklisted " + name);
          return null;
       }
-      
+
       // Ask the policy for the resource
       URL result = AccessController.doPrivileged(new PrivilegedAction<URL>()
       {
@@ -650,17 +704,17 @@
       // Cache what we found
       if (resourceCache != null && result != null)
          resourceCache.put(name, result);
-      
+
       // Blacklist when not found
       if (blackList != null && result == null)
          blackList.put(name, name);
-      
+
       return result;
    }
 
    /**
     * Try to find the resource locally
-    * 
+    *
     * @param name the resource name
     * @param urls the urls to add to
     * @throws IOException for any error
@@ -673,7 +727,7 @@
 
    /**
     * Try to find the resources locally
-    * 
+    *
     * @param name the resource name
     * @param urls the urls to add to
     * @param trace whether trace is enabled
@@ -709,7 +763,7 @@
          throw e2;
       }
    }
-   
+
    /**
     * Define the package for the class if not already done
     *
@@ -721,10 +775,10 @@
       String packageName = ClassLoaderUtils.getClassPackageName(className);
       if (packageName.length() == 0)
          return;
-      
+
       // Ask the policy for the information
       PackageInformation pi = policy.getClassPackageInformation(className, packageName);
-      
+
       // Already defined?
       Package pkge = getPackage(packageName);
       if (pkge != null)
@@ -761,7 +815,7 @@
 
    /**
     * Try to load the class from the domain
-    * 
+    *
     * @param name the class name
     * @param trace whether trace is enabled
     * @return the class if found in the parent
@@ -771,17 +825,17 @@
    {
       // Because of the broken classloading in the Sun JDK we need to
       // serialize access to the classloader.
-      
+
       // Additionally, acquiring the lock on the policy for this classloader
       // ensures that we don't race with somebody undeploying the classloader
       // which could cause leaks
       acquireLockFairly(trace);
       try
       {
-         // Here we have synchronized with the policy 
+         // Here we have synchronized with the policy
          BaseClassLoaderPolicy basePolicy = policy;
          BaseClassLoaderDomain domain = basePolicy.getClassLoaderDomain();
-         
+
          if (trace)
             log.trace(this + " load from domain " + name + " domain=" + domain);
 
@@ -791,7 +845,7 @@
          if (domain == null)
          {
             Class<?> result = loadClassLocally(name, trace);
-            
+
             // So this is almost certainly a classloader leak
             if (result == null)
                throw new IllegalStateException(this + " classLoader is not connected to a domain (probably undeployed?) for class " + name);
@@ -815,7 +869,7 @@
       BaseClassLoaderPolicy basePolicy = policy;
       return basePolicy.getClassLoaderUnchecked() != null;
    }
-   
+
    public Class<?> getCachedClass(String name)
    {
       // TODO look in global and/or local cache
@@ -880,10 +934,10 @@
          policy.clearBlackList(name);
       }
    }
-   
+
    /**
     * A long version of the classloader
-    * 
+    *
     * @return the long string
     */
    public String toLongString()
@@ -896,28 +950,29 @@
       builder.append('}');
       return builder.toString();
    }
-   
+
    /**
     * Shutdown the classloader
     */
    protected void shutdownClassLoader()
    {
       log.debug(toString() + " shutdown!");
+      loadedClasses.clear();
       if (resourceCache != null)
          resourceCache.clear();
       if (blackList != null)
          blackList.clear();
    }
-   
+
    /**
     * For subclasses to add things to the long string
-    * 
+    *
     * @param builder the builder
     */
    protected void toLongString(StringBuilder builder)
    {
    }
-   
+
    @Override
    public String toString()
    {
@@ -930,7 +985,7 @@
 
    /**
     * Attempt to lock, but don't wait
-    * 
+    *
     * @return true when the lock was obtained
     */
    boolean attemptLock()
@@ -940,7 +995,7 @@
 
    /**
     * Lock
-    * 
+    *
     * This method must be invoked with the monitor held
     */
    void lock()
@@ -950,7 +1005,7 @@
 
    /**
     * Unlock
-    * 
+    *
     * @param rescheduleTasks whether to reschedule tasks
     */
    void unlock(boolean rescheduleTasks)
@@ -960,7 +1015,7 @@
 
    /**
     * Attempt to get the lock but don't wait
-    * 
+    *
     * @param trace whether trace is enabled
     * @return true when obtained the lock
     */
@@ -1000,12 +1055,12 @@
 
       return result;
    }
-   
+
    /**
     * Acquire the lock on the classloader fairly<p>
     *
     * This must be invoked with the monitor held
-    * 
+    *
     * @param trace whether trace is enabled
     */
    private void acquireLockFairly(boolean trace)
@@ -1017,7 +1072,7 @@
       boolean interrupted = Thread.interrupted();
 
       int waits = 0;
-      
+
       try
       {
          while (true)
@@ -1052,14 +1107,14 @@
          if (interrupted)
             thread.interrupt();
       }
-      
+
       if (lock.getHoldCount() == 1)
          ClassLoaderManager.registerLoaderThread(this, thread);
    }
 
    /**
     * Unlock
-    * 
+    *
     * @param trace whether trace is enabled
     * @param rescheduleTasks whether to reschedule tasks
     */
@@ -1071,8 +1126,8 @@
 
       synchronized (this)
       {
-         lock.unlock();      
-      
+         lock.unlock();
+
          if (lock.getHoldCount() == 0)
          {
             ClassLoaderManager.unregisterLoaderThread(this, thread, rescheduleTasks);
@@ -1083,7 +1138,7 @@
    
    /**
     * Get the classloader for a class
-    * 
+    *
     * @param clazz the class
     * @return the classloader or null if it doesn't have one
     */
@@ -1092,7 +1147,7 @@
       SecurityManager sm = System.getSecurityManager();
       if (sm == null)
          return clazz.getClassLoader();
-      
+
       return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>()
       {
          public ClassLoader run()

Modified: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderDomain.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderDomain.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderDomain.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -1195,6 +1195,23 @@
    }
 
    /**
+    * Get the classloader policy associated with an object
+    * 
+    * @param object the  object
+    * @return the classloader policy or null if one is not associated
+    */
+   protected ClassLoaderPolicy getClassLoaderPolicy(Object object)
+   {
+      if (object instanceof BaseClassLoader)
+         return ((BaseClassLoader) object).getPolicy();
+      
+      if (object instanceof BaseClassLoaderSource)
+         return getClassLoaderPolicy(((BaseClassLoaderSource) object).getClassLoader());
+      
+      return null;
+   }
+   
+   /**
     * A long version of toString()
     * 
     * @return the long string

Modified: projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderPolicy.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderPolicy.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/main/java/org/jboss/classloader/spi/base/BaseClassLoaderPolicy.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -256,6 +256,16 @@
     * 
     * @return the domain
     */
+   protected ClassLoaderDomain getDomain()
+   {
+      return (ClassLoaderDomain) getClassLoaderDomain();
+   }
+   
+   /**
+    * Get the classloader domain
+    * 
+    * @return the domain
+    */
    BaseClassLoaderDomain getClassLoaderDomain()
    {
       return domain;
@@ -336,7 +346,7 @@
       log.debug(toString() + " shutdown!");
       BaseClassLoader classLoader = this.classLoader;
       this.classLoader = null;
-      TranslatorUtils.applyTranslatorsAtUnregister(getTranslators(), classLoader);
+      TranslatorUtils.applyTranslatorsAtUnregister(translators, classLoader);
       classLoader.shutdownClassLoader();
    }
    

Modified: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/ClassLoaderAllTestSuite.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/ClassLoaderAllTestSuite.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/ClassLoaderAllTestSuite.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -30,6 +30,7 @@
 import org.jboss.test.classloader.filter.FilterTestSuite;
 import org.jboss.test.classloader.jmx.JMXTestSuite;
 import org.jboss.test.classloader.junit.JUnitTestSuite;
+import org.jboss.test.classloader.notifications.ClassLoaderNotificationsTestSuite;
 import org.jboss.test.classloader.old.OldTestSuite;
 import org.jboss.test.classloader.policy.test.ClassLoaderPolicyUnitTestCase;
 import org.jboss.test.classloader.resources.ResourceTestSuite;
@@ -75,6 +76,7 @@
       suite.addTest(JMXTestSuite.suite());
       suite.addTest(JUnitTestSuite.suite());
       suite.addTest(TransformTestSuite.suite());
+      suite.addTest(ClassLoaderNotificationsTestSuite.suite());
 
       return suite;
    }

Modified: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/domain/test/CustomParentLoaderUnitTestCase.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/domain/test/CustomParentLoaderUnitTestCase.java	2009-11-18 16:43:33 UTC (rev 96495)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/domain/test/CustomParentLoaderUnitTestCase.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -29,9 +29,11 @@
 import junit.framework.Test;
 
 import org.jboss.classloader.plugins.ClassLoaderUtils;
+import org.jboss.classloader.spi.ClassFoundHandler;
 import org.jboss.classloader.spi.ClassLoaderDomain;
 import org.jboss.classloader.spi.ClassLoaderDomainMBean;
 import org.jboss.classloader.spi.ClassLoaderSystem;
+import org.jboss.classloader.spi.ClassNotFoundHandler;
 import org.jboss.classloader.spi.Loader;
 import org.jboss.classloader.spi.ParentPolicy;
 import org.jboss.classloader.spi.base.BaseClassLoaderDomain;
@@ -159,7 +161,7 @@
       ClassLoader classLoader = system.registerClassLoaderPolicy(domain, policy);
       
       assertLoadClass(ClassLoaderDomain.class, classLoader);
-      checkGetResource(loader, ClassLoaderDomain.class, BaseClassLoaderDomain.class, ClassLoaderDomainMBean.class, MBeanRegistration.class, Loader.class, Object.class);
+      checkGetResource(loader, ClassLoaderDomain.class, BaseClassLoaderDomain.class, ClassLoaderDomainMBean.class, MBeanRegistration.class, Loader.class, ClassNotFoundHandler.class, ClassFoundHandler.class, Object.class);
       checkLoadClass(loader);
    }
    

Added: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/ClassLoaderNotificationsTestSuite.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/ClassLoaderNotificationsTestSuite.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/ClassLoaderNotificationsTestSuite.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.test.classloader.notifications;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.jboss.test.classloader.notifications.test.ClassFoundHandlerUnitTestCase;
+import org.jboss.test.classloader.notifications.test.ClassLoaderEventHandlerUnitTestCase;
+import org.jboss.test.classloader.notifications.test.ClassNotFoundHandlerUnitTestCase;
+
+/**
+ * Notifications Test Suite.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 37459 $
+ */
+public class ClassLoaderNotificationsTestSuite extends TestSuite
+{
+   /**
+    * For running the testsuite from the command line
+    * 
+    * @param args the command line args
+    */
+   public static void main(String[] args)
+   {
+      TestRunner.run(suite());
+   }
+
+   /**
+    * Create the testsuite
+    * 
+    * @return the testsuite
+    */
+   public static Test suite()
+   {
+      TestSuite suite = new TestSuite("Notifications Tests");
+
+      suite.addTest(ClassLoaderEventHandlerUnitTestCase.suite());
+      suite.addTest(ClassNotFoundHandlerUnitTestCase.suite());
+      suite.addTest(ClassFoundHandlerUnitTestCase.suite());
+      
+      return suite;
+   }
+}

Added: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/support/a/A.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/support/a/A.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/support/a/A.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,32 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file 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.test.classloader.notifications.support.a;
+
+/**
+ * A.
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class A
+{
+}

Added: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassFoundHandlerUnitTestCase.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassFoundHandlerUnitTestCase.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassFoundHandlerUnitTestCase.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,286 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.test.classloader.notifications.test;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import junit.framework.Test;
+
+import org.jboss.classloader.plugins.loader.ClassLoaderToLoaderAdapter;
+import org.jboss.classloader.spi.ClassFoundEvent;
+import org.jboss.classloader.spi.ClassFoundHandler;
+import org.jboss.classloader.spi.ClassLoaderDomain;
+import org.jboss.classloader.spi.ClassLoaderSystem;
+import org.jboss.classloader.spi.ParentPolicy;
+import org.jboss.classloader.test.support.MockClassLoaderPolicy;
+import org.jboss.test.classloader.AbstractClassLoaderTestWithSecurity;
+import org.jboss.test.classloader.notifications.support.a.A;
+
+/**
+ * ClassFoundHnadlerUnitTestCase
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClassFoundHandlerUnitTestCase extends AbstractClassLoaderTestWithSecurity implements ClassFoundHandler
+{
+   public static Test suite()
+   {
+      return suite(ClassFoundHandlerUnitTestCase.class);
+   }
+
+   public ClassFoundHandlerUnitTestCase(String name)
+   {
+      super(name);
+   }
+   
+   List<ClassFoundEvent> events = new CopyOnWriteArrayList<ClassFoundEvent>();
+   
+   public void classFound(ClassFoundEvent event)
+   {
+      events.add(event);
+   }
+
+   public void testClassFoundHandlerPolicy() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setPathsAndPackageNames(A.class);
+      policy.addClassFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertLoadClass(A.class, cl);
+      assertLoadClassNoEvent(A.class, cl);
+   }
+
+   public void testClassFoundHandlerDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setPathsAndPackageNames(A.class);
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClass(A.class, cl);
+      assertLoadClassNoEvent(A.class, cl);
+   }
+
+   public void testClassFoundHandlerParentDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, defaultDomain);
+      defaultDomain.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setPathsAndPackageNames(A.class);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClass(A.class, cl, parentCl);
+      assertLoadClassNoEvent(A.class, cl, parentCl);
+   }
+
+   public void testClassFoundHandlerParentClassLoader() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      defaultDomain.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setPathsAndPackageNames(A.class);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, new ClassLoaderToLoaderAdapter(parentCl));
+      domain.setUseLoadClassForParent(false);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClass(A.class, cl, parentCl);
+      assertLoadClassNoEvent(A.class, cl, parentCl);
+   }
+
+   public void testClassFoundHandlerSystem() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setPathsAndPackageNames(A.class);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertLoadClass(A.class, cl);
+      assertLoadClassNoEvent(A.class, cl);
+   }
+
+   public void testClassFoundHandlerPolicyNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setPathsAndPackageNames(A.class);
+      policy.addClassFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertLoadClassFail("does.not.exist.Class", cl);
+   }
+
+   public void testClassFoundHandlerDomainNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setPathsAndPackageNames(A.class);
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClassFail("does.not.exist.Class", cl);
+   }
+
+   public void testClassFoundHandlerParentDomainNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, defaultDomain);
+      defaultDomain.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setPathsAndPackageNames(A.class);
+      system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClassFail("does.not.exist.Class", cl);
+   }
+
+   public void testClassFoundHandlerParentClassLoaderNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      defaultDomain.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setPathsAndPackageNames(A.class);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, new ClassLoaderToLoaderAdapter(parentCl));
+      domain.setUseLoadClassForParent(false);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClassFail("does.not.exist.Class", cl);
+   }
+
+   public void testClassFoundHandlerSystemNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.addClassFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setPathsAndPackageNames(A.class);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertLoadClassFail("does.not.exist.Class", cl);
+   }
+
+   public void testClassFoundHandlerWrongPolicy() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      policy.addClassFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      ClassLoader clA = system.registerClassLoaderPolicy(a);
+
+      assertLoadClassNoEvent(A.class, cl, clA);
+   }
+
+   public void testClassFoundHandlerDifferentPolicy() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      a.addClassFoundHandler(this);
+      ClassLoader clA = system.registerClassLoaderPolicy(a);
+
+      assertLoadClass(A.class, cl, clA);
+      assertLoadClassNoEvent(A.class, cl, clA);
+   }
+
+   protected Class<?> assertLoadClassNoEvent(Class<?> reference, ClassLoader start)
+   {
+      return assertLoadClass(reference, start, start);
+   }
+
+   protected Class<?> assertLoadClassNoEvent(Class<?> reference, ClassLoader start, ClassLoader expected)
+   {
+      Class<?> result = super.assertLoadClass(reference, start, expected);
+      assertNoEvent();
+      return result;
+   }
+
+   protected Class<?> assertLoadClass(Class<?> reference, ClassLoader start, ClassLoader expected)
+   {
+      Class<?> result = super.assertLoadClass(reference, start, expected);
+      assertEvent(reference.getName(), expected);
+      return result;
+   }
+
+   protected void assertLoadClassFail(String name, ClassLoader start)
+   {
+      super.assertLoadClassFail(name, start);
+      assertNoEvent();
+   }
+
+   protected void assertEvent(String name, ClassLoader expected)
+   {
+      assertTrue("Expected an event", events.isEmpty() == false);
+      ClassFoundEvent event = events.remove(0);
+      assertEquals(name, event.getClassName());
+      assertEquals(expected, event.getClassLoader());
+      assertEquals(expected, event.getSource());
+   }
+
+   protected void assertNoEvent()
+   {
+      assertTrue("Expected no events: " + events, events.isEmpty());
+   }
+}

Added: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassLoaderEventHandlerUnitTestCase.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassLoaderEventHandlerUnitTestCase.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassLoaderEventHandlerUnitTestCase.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,186 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.test.classloader.notifications.test;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import junit.framework.Test;
+
+import org.jboss.classloader.spi.ClassLoaderDomain;
+import org.jboss.classloader.spi.ClassLoaderEvent;
+import org.jboss.classloader.spi.ClassLoaderEventHandler;
+import org.jboss.classloader.spi.ClassLoaderSystem;
+import org.jboss.classloader.test.support.MockClassLoaderPolicy;
+import org.jboss.test.classloader.AbstractClassLoaderTestWithSecurity;
+
+/**
+ * ClassFoundHnadlerUnitTestCase
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClassLoaderEventHandlerUnitTestCase extends AbstractClassLoaderTestWithSecurity implements ClassLoaderEventHandler
+{
+   public static Test suite()
+   {
+      return suite(ClassLoaderEventHandlerUnitTestCase.class);
+   }
+
+   public ClassLoaderEventHandlerUnitTestCase(String name)
+   {
+      super(name);
+   }
+   
+   List<ClassLoaderEvent> registered = new CopyOnWriteArrayList<ClassLoaderEvent>();
+   List<ClassLoaderEvent> unregistered = new CopyOnWriteArrayList<ClassLoaderEvent>();
+   
+   public void fireRegisterClassLoader(ClassLoaderEvent event)
+   {
+      registered.add(event);
+   }
+   
+   public void fireUnregisterClassLoader(ClassLoaderEvent event)
+   {
+      unregistered.add(event);
+   }
+
+   public void testClassLoaderEventDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassLoaderEventHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertRegistered(domain, cl);
+      
+      system.unregisterClassLoader(cl);
+      assertUnregistered(domain, cl);
+   }
+
+   public void testClassLoaderEventSystem() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      system.addClassLoaderEventHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertRegistered(domain, cl);
+      
+      system.unregisterClassLoader(cl);
+      assertUnregistered(domain, cl);
+   }
+
+   public void testClassLoaderEventWrongDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain1 = system.createAndRegisterDomain("Domain1");
+      ClassLoaderDomain domain2 = system.createAndRegisterDomain("Domain2");
+      domain1.addClassLoaderEventHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain2, policy);
+
+      assertNoRegistered();
+      
+      system.unregisterClassLoader(cl);
+      assertNoUnregistered();
+   }
+
+   public void testClassLoaderEventCorrectDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.createAndRegisterDomain("Domain1");
+      ClassLoaderDomain domain2 = system.createAndRegisterDomain("Domain2");
+      domain2.addClassLoaderEventHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain2, policy);
+
+      assertRegistered(domain2, cl);
+      
+      system.unregisterClassLoader(cl);
+      assertUnregistered(domain2, cl);
+   }
+
+   public void testClassLoaderEventShutdownDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassLoaderEventHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertRegistered(domain, cl);
+      
+      system.shutdown();
+      assertUnregistered(domain, cl);
+   }
+
+   public void testClassLoaderEventShutdownSystem() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      system.addClassLoaderEventHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertRegistered(domain, cl);
+      
+      system.shutdown();
+      assertUnregistered(domain, cl);
+   }
+
+   protected void assertRegistered(ClassLoaderDomain domain, ClassLoader expected)
+   {
+      assertTrue("Expected a registered", registered.isEmpty() == false);
+      ClassLoaderEvent event = registered.remove(0);
+      assertEquals(domain, event.getClassLoaderDomain());
+      assertEquals(domain, event.getSource());
+      assertEquals(expected, event.getClassLoader());
+   }
+
+   protected void assertNoRegistered()
+   {
+      assertTrue("Expected no registered: " + registered, registered.isEmpty());
+   }
+
+   protected void assertUnregistered(ClassLoaderDomain domain, ClassLoader expected)
+   {
+      assertTrue("Expected an unregistered", unregistered.isEmpty() == false);
+      ClassLoaderEvent event = unregistered.remove(0);
+      assertEquals(domain, event.getClassLoaderDomain());
+      assertEquals(domain, event.getSource());
+      assertEquals(expected, event.getClassLoader());
+   }
+
+   protected void assertNoUnregistered()
+   {
+      assertTrue("Expected no unregistered: " + unregistered, unregistered.isEmpty());
+   }
+}

Added: projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassNotFoundHandlerUnitTestCase.java
===================================================================
--- projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassNotFoundHandlerUnitTestCase.java	                        (rev 0)
+++ projects/jboss-cl/trunk/classloader/src/test/java/org/jboss/test/classloader/notifications/test/ClassNotFoundHandlerUnitTestCase.java	2009-11-18 16:54:13 UTC (rev 96496)
@@ -0,0 +1,484 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.test.classloader.notifications.test;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import junit.framework.Test;
+
+import org.jboss.classloader.plugins.ClassLoaderUtils;
+import org.jboss.classloader.plugins.loader.ClassLoaderToLoaderAdapter;
+import org.jboss.classloader.spi.ClassLoaderDomain;
+import org.jboss.classloader.spi.ClassLoaderPolicy;
+import org.jboss.classloader.spi.ClassLoaderSystem;
+import org.jboss.classloader.spi.ClassNotFoundEvent;
+import org.jboss.classloader.spi.ClassNotFoundHandler;
+import org.jboss.classloader.spi.ParentPolicy;
+import org.jboss.classloader.test.support.MockClassLoaderPolicy;
+import org.jboss.test.classloader.AbstractClassLoaderTestWithSecurity;
+import org.jboss.test.classloader.notifications.support.a.A;
+
+/**
+ * ClassNotFoundHnadlerUnitTestCase
+ * 
+ * @author <a href="adrian at jboss.com">Adrian Brock</a>
+ * @version $Revision: 1.1 $
+ */
+public class ClassNotFoundHandlerUnitTestCase extends AbstractClassLoaderTestWithSecurity implements ClassNotFoundHandler
+{
+   public static Test suite()
+   {
+      return suite(ClassNotFoundHandlerUnitTestCase.class);
+   }
+
+   public ClassNotFoundHandlerUnitTestCase(String name)
+   {
+      super(name);
+   }
+   
+   List<ClassNotFoundEvent> events = new CopyOnWriteArrayList<ClassNotFoundEvent>();
+   
+   RegisterClassLoader runnable = null;
+   
+   public boolean classNotFound(ClassNotFoundEvent event)
+   {
+      events.add(event);
+
+      if (runnable != null)
+      {
+         runnable.run();
+         return true;
+      }
+      return false;
+   }
+
+   public void testClassNotFoundHandlerPolicy() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.addClassNotFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerSystem() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerParentDomain() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, defaultDomain);
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerParentClassLoader() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.addClassNotFoundHandler(this);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, new ClassLoaderToLoaderAdapter(parentCl));
+      domain.setUseLoadClassForParent(false);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerPolicyNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      policy.addClassNotFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      ClassLoader expected = system.registerClassLoaderPolicy(a);
+
+      assertLoadClassNoEvent(A.class, cl, expected);
+   }
+
+   public void testClassNotFoundHandlerDomainNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      ClassLoader expected = system.registerClassLoaderPolicy(a);
+
+      assertLoadClassNoEvent(A.class, cl, expected);
+   }
+
+   public void testClassNotFoundHandlerParentDomainNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, defaultDomain);
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      ClassLoader expected = system.registerClassLoaderPolicy(a);
+
+      assertLoadClassNoEvent(A.class, cl, expected);
+   }
+
+   public void testClassNotFoundHandlerParentClassLoaderNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setImportAll(true);
+      parentPolicy.addClassNotFoundHandler(this);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, new ClassLoaderToLoaderAdapter(parentCl));
+      domain.setUseLoadClassForParent(false);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      ClassLoader expected = system.registerClassLoaderPolicy(a);
+
+      assertLoadClassNoEvent(A.class, cl, expected);
+   }
+
+   public void testClassNotFoundHandlerSystemNoEvent() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy a = createMockClassLoaderPolicy("a");
+      a.setPathsAndPackageNames(A.class);
+      ClassLoader expected = system.registerClassLoaderPolicy(a);
+
+      assertLoadClassNoEvent(A.class, cl, expected);
+   }
+
+   public void testClassNotFoundHandlerPolicyResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      policy.addClassNotFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClass(A.class, cl, runnable);
+      assertLoadClassNoEvent(A.class, cl, runnable.getClassLoader());
+   }
+
+   public void testClassNotFoundHandlerDomainResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, domain, resolved);
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+      assertLoadClassNoEvent(A.class, cl, runnable.getClassLoader());
+   }
+
+   public void testClassNotFoundHandlerParentDomainResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, defaultDomain);
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClass(A.class, cl, runnable);
+      assertLoadClassNoEvent(A.class, cl, runnable.getClassLoader());
+   }
+
+   public void testClassNotFoundHandlerParentClassLoaderResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setImportAll(true);
+      parentPolicy.addClassNotFoundHandler(this);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, new ClassLoaderToLoaderAdapter(parentCl));
+      domain.setUseLoadClassForParent(false);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClass(A.class, cl, runnable);
+      assertLoadClassNoEvent(A.class, cl, runnable.getClassLoader());
+   }
+
+   public void testClassNotFoundHandlerSystemResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClass(A.class, cl, runnable);
+      assertLoadClassNoEvent(A.class, cl, runnable.getClassLoader());
+   }
+
+   public void testClassNotFoundHandlerPolicyNotResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      policy.addClassNotFoundHandler(this);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerDomainNotResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain domain = system.getDefaultDomain();
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, domain, resolved);
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerParentDomainNotResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, defaultDomain);
+      domain.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerParentClassLoaderNotResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      ClassLoaderDomain defaultDomain = system.getDefaultDomain();
+
+      MockClassLoaderPolicy parentPolicy = createMockClassLoaderPolicy("parent");
+      parentPolicy.setImportAll(true);
+      parentPolicy.addClassNotFoundHandler(this);
+      ClassLoader parentCl = system.registerClassLoaderPolicy(defaultDomain, parentPolicy);
+
+      ClassLoaderDomain domain = system.createAndRegisterDomain("TestDomain", ParentPolicy.BEFORE, new ClassLoaderToLoaderAdapter(parentCl));
+      domain.setUseLoadClassForParent(false);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      ClassLoader cl = system.registerClassLoaderPolicy(domain, policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   public void testClassNotFoundHandlerSystemNotResolved() throws Exception
+   {
+      ClassLoaderSystem system = createClassLoaderSystemWithModifiedBootstrap();
+      system.addClassNotFoundHandler(this);
+
+      MockClassLoaderPolicy policy = createMockClassLoaderPolicy("test");
+      policy.setImportAll(true);
+      ClassLoader cl = system.registerClassLoaderPolicy(policy);
+
+      MockClassLoaderPolicy resolved = createMockClassLoaderPolicy("a");
+      resolved.setPathsAndPackageNames(A.class);
+      runnable = new RegisterClassLoader(system, null, resolved);
+      assertLoadClassFail("does.not.exist.ClassName", cl);
+   }
+
+   protected Class<?> assertLoadClassNoEvent(Class<?> reference, ClassLoader start, ClassLoader expected)
+   {
+      Class<?> result = assertLoadClass(reference, start, expected);
+      assertNoEvent();
+      return result;
+   }
+
+   protected Class<?> assertLoadClass(Class<?> reference, ClassLoader start, RegisterClassLoader runnable)
+   {
+      return assertLoadClass(reference, start, runnable, false);
+   }
+
+   protected Class<?> assertLoadClass(Class<?> reference, ClassLoader start, RegisterClassLoader runnable, boolean isReference)
+   {
+      String name = reference.getName();
+      Class<?> result = null;
+      try
+      {
+         result = start.loadClass(name);
+         getLog().debug("Got class: " + ClassLoaderUtils.classToString(result) + " for " + name + " from " + start);
+      }
+      catch (ClassNotFoundException e)
+      {
+         failure("Did not expect CNFE for " + name + " from " + start, e);
+      }
+      assertClassLoader(result, runnable.getClassLoader());
+      if (isReference)
+         assertClassEquality(reference, result);
+      else
+         assertNoClassEquality(reference, result);
+      assertEvent(name, start);
+      return result;
+   }
+
+   protected void assertLoadClassFail(String name, ClassLoader start)
+   {
+      super.assertLoadClassFail(name, start);
+      assertEvent(name, start);
+   }
+
+   protected void assertEvent(String name, ClassLoader start)
+   {
+      assertTrue("Expected an event", events.isEmpty() == false);
+      ClassNotFoundEvent event = events.remove(0);
+      assertEquals(name, event.getClassName());
+      assertEquals(start, event.getClassLoader());
+      assertEquals(start, event.getSource());
+   }
+
+   protected void assertNoEvent()
+   {
+      assertTrue("Expected no events: " + events, events.isEmpty());
+   }
+   
+   class RegisterClassLoader implements Runnable
+   {
+      private ClassLoaderSystem system;
+      private ClassLoaderDomain domain;
+      private ClassLoaderPolicy policy;
+      private ClassLoader classLoader;
+      
+      public RegisterClassLoader(ClassLoaderSystem system, ClassLoaderDomain domain, ClassLoaderPolicy policy)
+      {
+         this.system = system;
+         if (domain == null)
+            domain = system.getDefaultDomain();
+         this.domain = domain;
+         this.policy = policy;
+      }
+      
+      public void run()
+      {
+         classLoader = system.registerClassLoaderPolicy(domain, policy);
+      }
+      
+      public ClassLoader getClassLoader()
+      {
+         if (classLoader == null)
+            throw new Error("No classloader registered");
+         return classLoader;
+      }
+   }
+}




More information about the jboss-cvs-commits mailing list