You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2009/08/04 16:03:59 UTC

svn commit: r800803 - in /sling/trunk/bundles/commons/classloader/src: main/java/org/apache/sling/commons/classloader/ main/java/org/apache/sling/commons/classloader/impl/ test/java/org/apache/sling/commons/classloader/impl/

Author: cziegeler
Date: Tue Aug  4 14:03:59 2009
New Revision: 800803

URL: http://svn.apache.org/viewvc?rev=800803&view=rev
Log:
SLING-1070 : Change class loading of package admin class loader to parent first, cache classes and resources in the class loader facade and reregister manager factory, if a used bundle is changed.

Modified:
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/Activator.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/BundleProxyClassLoader.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/ClassLoaderFacade.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerFactory.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java
    sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/PackageAdminClassLoader.java
    sling/trunk/bundles/commons/classloader/src/test/java/org/apache/sling/commons/classloader/impl/ClassLoadingTest.java

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/ClassLoaderWriter.java Tue Aug  4 14:03:59 2009
@@ -30,13 +30,45 @@
  */
 public interface ClassLoaderWriter {
 
-    OutputStream getOutputStream(String name);
+    /**
+     * Get the output stream for a class or resource handled
+     * by the underlying class loader.
+     * If the resource/class does not exists it should be created.
+     * @param path The path of the class/resource.
+     * @return The output stream.
+     */
+    OutputStream getOutputStream(String path);
 
-    InputStream getInputStream(String name) throws IOException;
+    /**
+     * Get the input stream for a class or resource handled
+     * by the underlying class loader.
+     * @param path The path of the class/resource.
+     * @return The input stream for the resource/class.
+     * @throws IOException If the resource/class does not exist.
+     */
+    InputStream getInputStream(String path) throws IOException;
 
-    long getLastModified(String name);
+    /**
+     * Return the last modified for the class or resource.
+     * @param path The path of the class/resource.
+     * @return The last modified information or <code>-1</code> if
+     *         the information can't be detected.
+     */
+    long getLastModified(String path);
 
-    boolean delete(String name);
+    /**
+     * Delete the class/resource
+     * @param path The path of the class/resource.
+     * @return <code>true</code> if the resource exists and could be deleted,
+     *     <code>false</code> otherwise.
+     */
+    boolean delete(String path);
 
-    boolean rename(String oldName, String newName);
+    /**
+     * Rename a class/resource.
+     * @param oldPath The path of the class/resource.
+     * @param newPath The new path.
+     * @return <code>true</code> if the renaming has been successful.
+     */
+    boolean rename(String oldPath, String newPath);
 }

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/DynamicClassLoaderManager.java Tue Aug  4 14:03:59 2009
@@ -24,6 +24,11 @@
  * It provides a class loader that can be used by
  * bundles requiring access to all publically available
  * classes.
+ *
+ * The default implementation uses the package admin
+ * service to load classes and resources. The search
+ * path can be extended by providing
+ * {@link DynamicClassLoaderProvider}s.
  */
 public interface DynamicClassLoaderManager {
 

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/Activator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/Activator.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/Activator.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/Activator.java Tue Aug  4 14:03:59 2009
@@ -21,17 +21,21 @@
 import java.util.Hashtable;
 
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
-import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * This activator registers the dynamic class loader manager.
+ * It listens for bundle events and reregisters the class loader manager
+ * if a bundle event for a used bundle occurs.
  */
-public class Activator implements BundleActivator {
+public class Activator implements SynchronousBundleListener, BundleListener {
 
     /** Package admin service name */
     private static String PACKAGE_ADMIN_NAME = PackageAdmin.class.getName();
@@ -45,26 +49,39 @@
     /** The dynamic class loader service factory. */
     private DynamicClassLoaderManagerFactory service;
 
+    /** The bundle context. */
+    private BundleContext bundleContext;
+
     /**
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
-    public void start(BundleContext context) throws Exception {
-        this.packageAdminTracker = new ServiceTracker(context, PACKAGE_ADMIN_NAME, null);
+    public void start(BundleContext context) {
+        this.bundleContext = context;
+
+        this.packageAdminTracker = new ServiceTracker(this.bundleContext, PACKAGE_ADMIN_NAME, null);
         this.packageAdminTracker.open();
 
         // register service
+        this.registerManagerFactory();
+        this.bundleContext.addBundleListener(this);
+    }
+
+    /**
+     * Register the dynamic class loader manager factory.
+     */
+    protected void registerManagerFactory() {
         final Hashtable<String, String> props = new Hashtable<String, String>();
         props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Dynamic Class Loader Service");
         props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
-        this.service = new DynamicClassLoaderManagerFactory(context,
+        this.service = new DynamicClassLoaderManagerFactory(this.bundleContext,
                 (PackageAdmin)this.packageAdminTracker.getService());
-        this.serviceReg = context.registerService(new String[] {DynamicClassLoaderManager.class.getName()}, service, props);
+        this.serviceReg = this.bundleContext.registerService(new String[] {DynamicClassLoaderManager.class.getName()}, service, props);
     }
 
     /**
-     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+     * Unregister the dynamic class loader manager factory.
      */
-    public void stop(BundleContext context) throws Exception {
+    protected void unregisterManagerFactory() {
         if ( this.serviceReg != null ) {
             this.serviceReg.unregister();
             this.serviceReg = null;
@@ -72,9 +89,30 @@
         if ( this.service != null ) {
             this.service = null;
         }
+    }
+
+    /**
+     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+     */
+    public void stop(BundleContext context) {
+        context.removeBundleListener(this);
+        this.unregisterManagerFactory();
         if ( this.packageAdminTracker != null ) {
             this.packageAdminTracker.close();
             this.packageAdminTracker = null;
         }
+        this.bundleContext = null;
+    }
+
+    /**
+     * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
+     */
+    public void bundleChanged(BundleEvent event) {
+        final long bundleId = event.getBundle().getBundleId();
+        boolean needsUpdate = this.service.isBundleUsed(bundleId);
+        if ( needsUpdate ) {
+            this.unregisterManagerFactory();
+            this.registerManagerFactory();
+        }
     }
 }

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/BundleProxyClassLoader.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/BundleProxyClassLoader.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/BundleProxyClassLoader.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/BundleProxyClassLoader.java Tue Aug  4 14:03:59 2009
@@ -27,6 +27,8 @@
 /**
  * The <code>BundleProxyClassLoader</code> is a class loader
  * delegating to a bundle.
+ * We don't need to cache as the {@link ClassLoaderFacade} is
+ * already doing this.
  */
 public class BundleProxyClassLoader extends ClassLoader {
 

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/ClassLoaderFacade.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/ClassLoaderFacade.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/ClassLoaderFacade.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/ClassLoaderFacade.java Tue Aug  4 14:03:59 2009
@@ -19,19 +19,30 @@
 package org.apache.sling.commons.classloader.impl;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.URL;
 import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 
 /**
  * The <code>ClassLoaderFacade</code> is a facade
  * for the dynamic class loading.
+ * This class loader is returned to the clients of the
+ * dynamic class loader manager.
+ * This class loader delegates to other class loaders
+ * but caches its result for performance.
  */
 public class ClassLoaderFacade extends ClassLoader {
 
     private final DynamicClassLoaderManagerImpl manager;
 
+    /** A cache for resolved classes. */
+    private Map<String, Class<?>> classCache = new ConcurrentHashMap<String, Class<?>>();
+
+    /** A cache for resolved urls. */
+    private Map<String, URL> urlCache = new ConcurrentHashMap<String, URL>();
+
     public ClassLoaderFacade(final DynamicClassLoaderManagerImpl manager) {
         this.manager = manager;
     }
@@ -40,11 +51,19 @@
      * @see java.lang.ClassLoader#getResource(java.lang.String)
      */
     public URL getResource(String name) {
+        if ( !this.manager.isActive() ) {
+            throw new RuntimeException("Dynamic class loader has already been deactivated.");
+        }
+        final URL cachedURL = urlCache.get(name);
+        if ( cachedURL != null ) {
+            return cachedURL;
+        }
         final ClassLoader[] loaders = manager.getDynamicClassLoaders();
         for(final ClassLoader cl : loaders) {
             if ( cl != null ) {
                 final URL u = cl.getResource(name);
                 if ( u != null ) {
+                    urlCache.put(name, u);
                     return u;
                 }
             }
@@ -53,25 +72,12 @@
     }
 
     /**
-     * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
-     */
-    public InputStream getResourceAsStream(String name) {
-        final ClassLoader[] loaders = manager.getDynamicClassLoaders();
-        for(final ClassLoader cl : loaders) {
-            if ( cl != null ) {
-                final InputStream i = cl.getResourceAsStream(name);
-                if ( i != null ) {
-                    return i;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
      * @see java.lang.ClassLoader#getResources(java.lang.String)
      */
     public Enumeration<URL> getResources(String name) throws IOException {
+        if ( !this.manager.isActive() ) {
+            throw new RuntimeException("Dynamic class loader has already been deactivated.");
+        }
         final ClassLoader[] loaders = manager.getDynamicClassLoaders();
         for(final ClassLoader cl : loaders) {
             if ( cl != null ) {
@@ -88,13 +94,22 @@
      * @see java.lang.ClassLoader#loadClass(java.lang.String)
      */
     public Class<?> loadClass(String name) throws ClassNotFoundException {
+        if ( !this.manager.isActive() ) {
+            throw new RuntimeException("Dynamic class loader has already been deactivated.");
+        }
+        final Class<?> cachedClass = this.classCache.get(name);
+        if ( cachedClass != null ) {
+            return cachedClass;
+        }
         final ClassLoader[] loaders = manager.getDynamicClassLoaders();
         for(final ClassLoader cl : loaders) {
             if ( cl != null ) {
                 try {
                     final Class<?> c = cl.loadClass(name);
+                    this.classCache.put(name, c);
                     return c;
                 } catch (Exception cnfe) {
+                    cnfe.printStackTrace();
                     // we just ignore this and try the next class loader
                 }
             }

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerFactory.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerFactory.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerFactory.java Tue Aug  4 14:03:59 2009
@@ -16,6 +16,10 @@
  */
 package org.apache.sling.commons.classloader.impl;
 
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceFactory;
@@ -34,6 +38,8 @@
     /** The bundle context. */
     private final BundleContext context;
 
+    private final Set<Long> usedBundles = Collections.synchronizedSet(new HashSet<Long>());
+
     /**
      * Create a new service instance
      * @param ctx The bundle context.
@@ -50,7 +56,7 @@
      */
     public Object getService(final Bundle bundle,
                              final ServiceRegistration registration) {
-        return new DynamicClassLoaderManagerImpl(this.context, this.pckAdmin, new BundleProxyClassLoader(bundle));
+        return new DynamicClassLoaderManagerImpl(this.context, this.pckAdmin, new BundleProxyClassLoader(bundle), this);
     }
 
     /**
@@ -63,4 +69,22 @@
             ((DynamicClassLoaderManagerImpl)service).deactivate();
         }
     }
+
+    /**
+     * Check if a bundle has been used for class loading.
+     * @param bundleId The bundle id.
+     * @return <code>true</code> if the bundle has been used.
+     */
+    public boolean isBundleUsed(final long bundleId) {
+        return usedBundles.contains(bundleId);
+    }
+
+    /**
+     * Notify that a bundle is used as a source for class loading.
+     * @param bundle The bundle.
+     */
+    public void addUsedBundle(final Bundle bundle) {
+        final long id = bundle.getBundleId();
+        this.usedBundles.add(id);
+    }
 }

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/DynamicClassLoaderManagerImpl.java Tue Aug  4 14:03:59 2009
@@ -44,10 +44,15 @@
     /** The bundle context. */
     private final BundleContext context;
 
+    /** The cached chain of class loaders. */
     private ClassLoader[] cache;
 
+    /** Needs the cache an update? */
     private boolean updateCache = false;
 
+    /** Is this service still active? */
+    private boolean active = true;
+
     /**
      * Create a new service instance
      * @param ctx The bundle context of the class loader bundle
@@ -56,10 +61,11 @@
      */
     public DynamicClassLoaderManagerImpl(final BundleContext ctx,
             final PackageAdmin pckAdmin,
-            final ClassLoader parent) {
+            final ClassLoader parent,
+            final DynamicClassLoaderManagerFactory factory) {
         super(ctx, DynamicClassLoaderProvider.class.getName(), null);
         this.context = ctx;
-        this.pckAdminCL = new PackageAdminClassLoader(pckAdmin, parent);
+        this.pckAdminCL = new PackageAdminClassLoader(pckAdmin, parent, factory);
         this.cache = new ClassLoader[] {this.pckAdminCL};
         this.open();
         this.facade = new ClassLoaderFacade(this);
@@ -85,8 +91,7 @@
             final ServiceReference[] refs = this.getServiceReferences();
             final ClassLoader[] loaders = new ClassLoader[1 + refs.length];
             Arrays.sort(refs, ServiceReferenceComparator.INSTANCE);
-            loaders[0] = this.pckAdminCL;
-            int index = 1;
+            int index = 0;
             for(final ServiceReference ref : refs) {
                 final DynamicClassLoaderProvider provider = (DynamicClassLoaderProvider)this.getService(ref);
                 if ( provider != null ) {
@@ -94,6 +99,7 @@
                 }
                 index++;
             }
+            loaders[index] = this.pckAdminCL;
             // and now use new array
             this.cache = loaders;
             this.updateCache = false;
@@ -104,9 +110,16 @@
      * Deactivate this service.
      */
     public void deactivate() {
+        this.active = false;
         this.close();
     }
 
+    /**
+     * Check if this service is still active.
+     */
+    public boolean isActive() {
+        return this.active;
+    }
 
     /**
      * @see org.apache.sling.commons.classloader.DynamicClassLoaderManager#getDynamicClassLoader()

Modified: sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/PackageAdminClassLoader.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/PackageAdminClassLoader.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/PackageAdminClassLoader.java (original)
+++ sling/trunk/bundles/commons/classloader/src/main/java/org/apache/sling/commons/classloader/impl/PackageAdminClassLoader.java Tue Aug  4 14:03:59 2009
@@ -27,28 +27,52 @@
 import org.osgi.service.packageadmin.PackageAdmin;
 
 /**
- * The <code>PackageAdminClassLoader</code>
+ * The <code>PackageAdminClassLoader</code> loads
+ * classes and resources through the package admin service.
  */
 class PackageAdminClassLoader extends ClassLoader {
 
+    /** The package admin service. */
     private final PackageAdmin packageAdmin;
 
-    public PackageAdminClassLoader(final PackageAdmin pckAdmin, final ClassLoader parent) {
+    /** The manager factory. */
+    private final DynamicClassLoaderManagerFactory factory;
+
+    public PackageAdminClassLoader(final PackageAdmin pckAdmin,
+                                   final ClassLoader parent,
+                                   final DynamicClassLoaderManagerFactory factory) {
         super(parent);
         this.packageAdmin = pckAdmin;
+        this.factory = factory;
     }
 
+    /**
+     * Find the bundle for a given package.
+     * @param pckName The package name.
+     * @return The bundle or <code>null</code>
+     */
     private Bundle findBundleForPackage(final String pckName) {
         final ExportedPackage exportedPackage = this.packageAdmin.getExportedPackage(pckName);
-        return (exportedPackage == null ? null : exportedPackage.getExportingBundle());
+        final Bundle bundle = (exportedPackage == null ? null : exportedPackage.getExportingBundle());
+        return bundle;
     }
 
+    /**
+     * Return the package from a resource.
+     * @param resource The resource path.
+     * @return The package name.
+     */
     private String getPackageFromResource(final String resource) {
         final int lastSlash = resource.lastIndexOf('/');
         final String pckName = (lastSlash == -1 ? "" : resource.substring(0, lastSlash).replace('/', '.'));
         return pckName;
     }
 
+    /**
+     * Return the package from a class.
+     * @param resource The class name.
+     * @return The package name.
+     */
     private String getPackageFromClassName(final String name) {
         final int lastDot = name.lastIndexOf('.');
         final String pckName = (lastDot == -1 ? "" : name.substring(0, lastDot));
@@ -60,43 +84,73 @@
      */
     @SuppressWarnings("unchecked")
     public Enumeration<URL> getResources(String name) throws IOException {
-        final Bundle bundle = this.findBundleForPackage(getPackageFromResource(name));
-        if ( bundle == null ) {
-            return super.getResources(name);
+        Enumeration<URL> e = super.getResources(name);
+        if ( e == null || !e.hasMoreElements() ) {
+            final Bundle bundle = this.findBundleForPackage(getPackageFromResource(name));
+            if ( bundle != null ) {
+                e = bundle.getResources(name);
+                if ( e != null && e.hasMoreElements() ) {
+                    this.factory.addUsedBundle(bundle);
+                }
+            }
         }
-        return bundle.getResources(name);
+        return e;
     }
 
     /**
      * @see java.lang.ClassLoader#findResource(java.lang.String)
      */
     public URL findResource(String name) {
-        final Bundle bundle = this.findBundleForPackage(getPackageFromResource(name));
-        if ( bundle == null ) {
-            return super.findResource(name);
+        URL url = super.findResource(name);
+        if ( url == null ) {
+            final Bundle bundle = this.findBundleForPackage(getPackageFromResource(name));
+            if ( bundle != null ) {
+                url = bundle.getResource(name);
+                if ( url != null ) {
+                    this.factory.addUsedBundle(bundle);
+                }
+            }
         }
-        return bundle.getResource(name);
+        return url;
     }
 
     /**
      * @see java.lang.ClassLoader#findClass(java.lang.String)
      */
     public Class<?> findClass(String name) throws ClassNotFoundException {
-        final Bundle bundle = this.findBundleForPackage(getPackageFromClassName(name));
-        if ( bundle == null ) {
-            return super.findClass(name);
+        Class<?> clazz = null;
+        try {
+            clazz = super.findClass(name);
+        } catch (ClassNotFoundException cnfe) {
+            final Bundle bundle = this.findBundleForPackage(getPackageFromClassName(name));
+            if ( bundle != null ) {
+                clazz = bundle.loadClass(name);
+                this.factory.addUsedBundle(bundle);
+            }
         }
-        return bundle.loadClass(name);
+        if ( clazz == null ) {
+            throw new ClassNotFoundException("Class not found " + name);
+        }
+        return clazz;
     }
 
     /**
      * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
      */
     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
-        final Bundle bundle = this.findBundleForPackage(getPackageFromClassName(name));
-        if ( bundle == null ) {
-            return super.loadClass(name, resolve);
+        Class<?> clazz = null;
+        try {
+            clazz = super.loadClass(name, resolve);
+        } catch (ClassNotFoundException cnfe) {
+            final Bundle bundle = this.findBundleForPackage(getPackageFromClassName(name));
+            if ( bundle != null ) {
+                clazz = bundle.loadClass(name);
+                this.factory.addUsedBundle(bundle);
+            }
+        }
+        if ( clazz == null ) {
+            throw new ClassNotFoundException("Class not found " + name);
         }
-        return bundle.loadClass(name);
+        return clazz;
     }
 }

Modified: sling/trunk/bundles/commons/classloader/src/test/java/org/apache/sling/commons/classloader/impl/ClassLoadingTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/classloader/src/test/java/org/apache/sling/commons/classloader/impl/ClassLoadingTest.java?rev=800803&r1=800802&r2=800803&view=diff
==============================================================================
--- sling/trunk/bundles/commons/classloader/src/test/java/org/apache/sling/commons/classloader/impl/ClassLoadingTest.java (original)
+++ sling/trunk/bundles/commons/classloader/src/test/java/org/apache/sling/commons/classloader/impl/ClassLoadingTest.java Tue Aug  4 14:03:59 2009
@@ -61,6 +61,8 @@
             will(returnValue(ep));
             allowing(ep).getExportingBundle();
             will(returnValue(bundle));
+            allowing(bundle).getBundleId();
+            will(returnValue(2L));
             one(bundle).loadClass("org.apache.sling.test.A"); inSequence(sequence);
             will(returnValue(java.util.Map.class));
             one(bundle).loadClass("org.apache.sling.test.A"); inSequence(sequence);
@@ -68,13 +70,15 @@
             one(bundle).loadClass("org.apache.sling.test.A"); inSequence(sequence);
             will(returnValue(java.util.ArrayList.class));
         }});
-        DynamicClassLoaderManagerImpl manager = new DynamicClassLoaderManagerImpl(bundleContext, packageAdmin, null);
+        DynamicClassLoaderManagerImpl manager = new DynamicClassLoaderManagerImpl(bundleContext, packageAdmin, null,
+            new DynamicClassLoaderManagerFactory(bundleContext, packageAdmin));
         final ClassLoader cl = manager.getDynamicClassLoader();
         final Class c1 = cl.loadClass("org.apache.sling.test.A");
         Assert.assertEquals("java.util.Map", c1.getName());
         final Class c2 = cl.loadClass("org.apache.sling.test.A");
         Assert.assertEquals("java.util.Map", c2.getName());
+        // as we cache the result, we still get the map!
         final Class c3 = cl.loadClass("org.apache.sling.test.A");
-        Assert.assertEquals("java.util.ArrayList", c3.getName());
+        Assert.assertEquals("java.util.Map", c3.getName());
     }
 }