package org.ops4j.pax.web.utils;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.List;
import org.apache.xbean.osgi.bundle.util.BundleResourceHelper;
import org.apache.xbean.osgi.bundle.util.DelegatingBundle;
import org.apache.xbean.osgi.bundle.util.DelegatingBundleReference;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleReference;
public class FelixBundleClassLoader extends URLClassLoader implements DelegatingBundleReference {
private final List<Bundle> bundles;
private final BundleResourceHelper resourceHelper;
private Bundle bundle;
public FelixBundleClassLoader(List<Bundle> bundles) {
super(new URL[] {});
this.bundles = bundles;
this.bundle = new DelegatingBundle(bundles);
this.resourceHelper = new FelixBundleResourceHelper(bundle, bundles);
}
@Override
public String toString() {
return "[FelixBundleClassLoader] " + bundles;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = bundle.loadClass(name);
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
@Override
public URL getResource(String name) {
return resourceHelper.getResource(name);
}
@Override
public Enumeration<URL> findResources(String name) throws IOException {
return resourceHelper.getResources(name);
}
/**
* Return the bundle associated with this classloader.
*
* In most cases the bundle associated with the classloader is a regular framework bundle.
* However, in some cases the bundle associated with the classloader is a {@link DelegatingBundle}.
* In such cases, the <tt>unwrap</tt> parameter controls whether this function returns the
* {@link DelegatingBundle} instance or the main application bundle backing with the {@link DelegatingBundle}.
*
* @param unwrap If true and if the bundle associated with this classloader is a {@link DelegatingBundle},
* this function will return the main application bundle backing with the {@link DelegatingBundle}.
* Otherwise, the bundle associated with this classloader is returned as is.
* @return The bundle associated with this classloader.
*/
public Bundle getBundle(boolean unwrap) {
if (unwrap && bundle instanceof DelegatingBundle) {
return ((DelegatingBundle) bundle).getMainBundle();
}
return bundle;
}
/**
* Return the bundle associated with this classloader.
*
* This method calls {@link #getBundle(boolean) getBundle(true)} and therefore always returns a regular
* framework bundle.
* <br><br>
* Note: Some libraries use {@link BundleReference#getBundle()} to obtain a bundle for the given
* classloader and expect the returned bundle instance to be work with any OSGi API. Some of these API might
* not work if {@link DelegatingBundle} is returned. That is why this function will always return
* a regular framework bundle. See {@link #getBundle(boolean)} for more information.
*
* @return The bundle associated with this classloader.
*/
public Bundle getBundle() {
return getBundle(true);
}
@Override
public int hashCode() {
return bundle.hashCode();
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (other == null || !other.getClass().equals(getClass())) {
return false;
}
FelixBundleClassLoader otherBundleClassLoader = (FelixBundleClassLoader) other;
return this.bundle == otherBundleClassLoader.bundle;
}
}