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());
}
}