Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java1270
1 files changed, 1270 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java
new file mode 100644
index 000000000..f972160de
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java
@@ -0,0 +1,1270 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.internal.loader;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import org.eclipse.osgi.framework.adaptor.*;
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.internal.core.*;
+import org.eclipse.osgi.framework.internal.core.Constants;
+import org.eclipse.osgi.framework.util.KeyedElement;
+import org.eclipse.osgi.framework.util.KeyedHashSet;
+import org.eclipse.osgi.internal.loader.buddy.PolicyHandler;
+import org.eclipse.osgi.internal.resolver.StateBuilder;
+import org.eclipse.osgi.service.resolver.*;
+import org.eclipse.osgi.util.ManifestElement;
+import org.osgi.framework.*;
+import org.osgi.framework.wiring.BundleWiring;
+
+/**
+ * This object is responsible for all classloader delegation for a bundle.
+ * It represents the loaded state of the bundle. BundleLoader objects
+ * are created lazily; care should be taken not to force the creation
+ * of a BundleLoader unless it is necessary.
+ * @see org.eclipse.osgi.internal.loader.BundleLoaderProxy
+ */
+public class BundleLoader implements ClassLoaderDelegate {
+ public final static String DEFAULT_PACKAGE = "."; //$NON-NLS-1$
+ public final static String JAVA_PACKAGE = "java."; //$NON-NLS-1$
+ public final static byte FLAG_IMPORTSINIT = 0x01;
+ public final static byte FLAG_HASDYNAMICIMPORTS = 0x02;
+ public final static byte FLAG_HASDYNAMICEIMPORTALL = 0x04;
+ public final static byte FLAG_CLOSED = 0x08;
+ public final static byte FLAG_LAZYTRIGGER = 0x10;
+
+ public final static ClassContext CLASS_CONTEXT = AccessController.doPrivileged(new PrivilegedAction<ClassContext>() {
+ public ClassContext run() {
+ return new ClassContext();
+ }
+ });
+ public final static ClassLoader FW_CLASSLOADER = getClassLoader(Framework.class);
+
+ private static final int PRE_CLASS = 1;
+ private static final int POST_CLASS = 2;
+ private static final int PRE_RESOURCE = 3;
+ private static final int POST_RESOURCE = 4;
+ private static final int PRE_RESOURCES = 5;
+ private static final int POST_RESOURCES = 6;
+ private static final int PRE_LIBRARY = 7;
+ private static final int POST_LIBRARY = 8;
+
+ /* the proxy */
+ final private BundleLoaderProxy proxy;
+ /* Bundle object */
+ final BundleHost bundle;
+ final private PolicyHandler policy;
+ /* List of package names that are exported by this BundleLoader */
+ final private Collection<String> exportedPackages;
+ final private Collection<String> substitutedPackages;
+ /* List of required bundle BundleLoaderProxy objects */
+ final BundleLoaderProxy[] requiredBundles;
+ /* List of indexes into the requiredBundles list of reexported bundles */
+ final int[] reexportTable;
+ /* cache of required package sources. Key is packagename, value is PackageSource */
+ final private KeyedHashSet requiredSources;
+
+ // note that the following non-final must be access using synchronization
+ /* cache of imported packages. Key is packagename, Value is PackageSource */
+ private KeyedHashSet importedSources;
+ /* If not null, list of package stems to import dynamically. */
+ private String[] dynamicImportPackageStems;
+ /* If not null, list of package names to import dynamically. */
+ private String[] dynamicImportPackages;
+ /* loader flags */
+ private byte loaderFlags = 0;
+ /* The is the BundleClassLoader for the bundle */
+ private BundleClassLoader classloader;
+ private ClassLoader parent;
+
+ /**
+ * Returns the package name from the specified class name.
+ * The returned package is dot seperated.
+ *
+ * @param name Name of a class.
+ * @return Dot separated package name or null if the class
+ * has no package name.
+ */
+ public final static String getPackageName(String name) {
+ if (name != null) {
+ int index = name.lastIndexOf('.'); /* find last period in class name */
+ if (index > 0)
+ return name.substring(0, index);
+ }
+ return DEFAULT_PACKAGE;
+ }
+
+ /**
+ * Returns the package name from the specified resource name.
+ * The returned package is dot seperated.
+ *
+ * @param name Name of a resource.
+ * @return Dot separated package name or null if the resource
+ * has no package name.
+ */
+ public final static String getResourcePackageName(String name) {
+ if (name != null) {
+ /* check for leading slash*/
+ int begin = ((name.length() > 1) && (name.charAt(0) == '/')) ? 1 : 0;
+ int end = name.lastIndexOf('/'); /* index of last slash */
+ if (end > begin)
+ return name.substring(begin, end).replace('/', '.');
+ }
+ return DEFAULT_PACKAGE;
+ }
+
+ /**
+ * BundleLoader runtime constructor. This object is created lazily
+ * when the first request for a resource is made to this bundle.
+ *
+ * @param bundle Bundle object for this loader.
+ * @param proxy the BundleLoaderProxy for this loader.
+ * @exception org.osgi.framework.BundleException
+ */
+ protected BundleLoader(BundleHost bundle, BundleLoaderProxy proxy) throws BundleException {
+ this.bundle = bundle;
+ this.proxy = proxy;
+ try {
+ bundle.getBundleData().open(); /* make sure the BundleData is open */
+ } catch (IOException e) {
+ throw new BundleException(Msg.BUNDLE_READ_EXCEPTION, e);
+ }
+ BundleDescription description = proxy.getBundleDescription();
+ // init the require bundles list.
+ BundleDescription[] required = description.getResolvedRequires();
+ if (required.length > 0) {
+ // get a list of re-exported symbolic names
+ Set<String> reExportSet = new HashSet<String>(required.length);
+ BundleSpecification[] requiredSpecs = description.getRequiredBundles();
+ if (requiredSpecs != null && requiredSpecs.length > 0)
+ for (int i = 0; i < requiredSpecs.length; i++)
+ if (requiredSpecs[i].isExported())
+ reExportSet.add(requiredSpecs[i].getName());
+
+ requiredBundles = new BundleLoaderProxy[required.length];
+ int[] reexported = new int[required.length];
+ int reexportIndex = 0;
+ for (int i = 0; i < required.length; i++) {
+ requiredBundles[i] = getLoaderProxy(required[i]);
+ if (reExportSet.contains(required[i].getSymbolicName()))
+ reexported[reexportIndex++] = i;
+ }
+ if (reexportIndex > 0) {
+ reexportTable = new int[reexportIndex];
+ System.arraycopy(reexported, 0, reexportTable, 0, reexportIndex);
+ } else {
+ reexportTable = null;
+ }
+ requiredSources = new KeyedHashSet(10, false);
+ } else {
+ requiredBundles = null;
+ reexportTable = null;
+ requiredSources = null;
+ }
+
+ // init the provided packages set
+ ExportPackageDescription[] exports = description.getSelectedExports();
+ if (exports != null && exports.length > 0) {
+ exportedPackages = Collections.synchronizedCollection(exports.length > 10 ? new HashSet<String>(exports.length) : new ArrayList<String>(exports.length));
+ initializeExports(exports, exportedPackages);
+ } else {
+ exportedPackages = Collections.synchronizedCollection(new ArrayList<String>(0));
+ }
+
+ ExportPackageDescription substituted[] = description.getSubstitutedExports();
+ if (substituted.length > 0) {
+ substitutedPackages = substituted.length > 10 ? new HashSet<String>(substituted.length) : new ArrayList<String>(substituted.length);
+ for (int i = 0; i < substituted.length; i++)
+ substitutedPackages.add(substituted[i].getName());
+ } else {
+ substitutedPackages = null;
+ }
+
+ //This is the fastest way to access to the description for fragments since the hostdescription.getFragments() is slow
+ BundleFragment[] fragmentObjects = bundle.getFragments();
+ BundleDescription[] fragments = new BundleDescription[fragmentObjects == null ? 0 : fragmentObjects.length];
+ for (int i = 0; i < fragments.length; i++)
+ fragments[i] = fragmentObjects[i].getBundleDescription();
+ // init the dynamic imports tables
+ if (description.hasDynamicImports())
+ addDynamicImportPackage(description.getImportPackages());
+ // ...and its fragments
+ for (int i = 0; i < fragments.length; i++)
+ if (fragments[i].isResolved() && fragments[i].hasDynamicImports())
+ addDynamicImportPackage(fragments[i].getImportPackages());
+
+ //Initialize the policy handler
+ String buddyList = null;
+ try {
+ buddyList = bundle.getBundleData().getManifest().get(Constants.BUDDY_LOADER);
+ } catch (BundleException e) {
+ // do nothing; buddyList == null
+ }
+ policy = buddyList != null ? new PolicyHandler(this, buddyList, bundle.getFramework().getPackageAdmin()) : null;
+ if (policy != null)
+ policy.open(bundle.getFramework().getSystemBundleContext());
+ }
+
+ private void initializeExports(ExportPackageDescription[] exports, Collection<String> exportNames) {
+ for (int i = 0; i < exports.length; i++) {
+ if (proxy.forceSourceCreation(exports[i])) {
+ if (!exportNames.contains(exports[i].getName())) {
+ // must force filtered and reexport sources to be created early
+ // to prevent lazy normal package source creation.
+ // We only do this for the first export of a package name.
+ proxy.createPackageSource(exports[i], true);
+ }
+ }
+ exportNames.add(exports[i].getName());
+ }
+ }
+
+ public synchronized KeyedHashSet getImportedSources(KeyedHashSet visited) {
+ if ((loaderFlags & FLAG_IMPORTSINIT) != 0)
+ return importedSources;
+ BundleDescription bundleDesc = proxy.getBundleDescription();
+ ExportPackageDescription[] packages = bundleDesc.getResolvedImports();
+ if (packages != null && packages.length > 0) {
+ if (importedSources == null)
+ importedSources = new KeyedHashSet(packages.length, false);
+ for (int i = 0; i < packages.length; i++) {
+ if (packages[i].getExporter() == bundleDesc)
+ continue; // ignore imports resolved to this bundle
+ PackageSource source = createExportPackageSource(packages[i], visited);
+ if (source != null)
+ importedSources.add(source);
+ }
+ }
+ loaderFlags |= FLAG_IMPORTSINIT;
+ return importedSources;
+ }
+
+ public synchronized boolean isLazyTriggerSet() {
+ return (loaderFlags & FLAG_LAZYTRIGGER) != 0;
+ }
+
+ public void setLazyTrigger() throws BundleException {
+ synchronized (this) {
+ loaderFlags |= FLAG_LAZYTRIGGER;
+ }
+ BundleLoaderProxy.secureAction.start(bundle, Bundle.START_TRANSIENT | BundleHost.LAZY_TRIGGER);
+ }
+
+ final PackageSource createExportPackageSource(ExportPackageDescription export, KeyedHashSet visited) {
+ BundleLoaderProxy exportProxy = getLoaderProxy(export.getExporter());
+ if (exportProxy == null)
+ // TODO log error!!
+ return null;
+ PackageSource requiredSource = exportProxy.getBundleLoader().findRequiredSource(export.getName(), visited);
+ PackageSource exportSource = exportProxy.createPackageSource(export, false);
+ if (requiredSource == null)
+ return exportSource;
+ return createMultiSource(export.getName(), new PackageSource[] {requiredSource, exportSource});
+ }
+
+ private static PackageSource createMultiSource(String packageName, PackageSource[] sources) {
+ if (sources.length == 1)
+ return sources[0];
+ List<SingleSourcePackage> sourceList = new ArrayList<SingleSourcePackage>(sources.length);
+ for (int i = 0; i < sources.length; i++) {
+ SingleSourcePackage[] innerSources = sources[i].getSuppliers();
+ for (int j = 0; j < innerSources.length; j++)
+ if (!sourceList.contains(innerSources[j]))
+ sourceList.add(innerSources[j]);
+ }
+ return new MultiSourcePackage(packageName, sourceList.toArray(new SingleSourcePackage[sourceList.size()]));
+ }
+
+ /*
+ * get the loader proxy for a bundle description
+ */
+ public final BundleLoaderProxy getLoaderProxy(BundleDescription source) {
+ Object userObject = source.getUserObject();
+ if (!(userObject instanceof BundleLoaderProxy)) {
+ // may need to force the proxy to be created
+ long exportingID = source.getBundleId();
+ BundleHost exportingBundle = (BundleHost) bundle.getFramework().getBundle(exportingID);
+ if (exportingBundle == null)
+ return null;
+ userObject = exportingBundle.getLoaderProxy();
+ }
+ return (BundleLoaderProxy) userObject;
+ }
+
+ public BundleLoaderProxy getLoaderProxy() {
+ return proxy;
+ }
+
+ /*
+ * Close the the BundleLoader.
+ *
+ */
+ synchronized void close() {
+ if ((loaderFlags & FLAG_CLOSED) != 0)
+ return;
+ if (classloader != null)
+ classloader.close();
+ if (policy != null)
+ policy.close(bundle.getFramework().getSystemBundleContext());
+ loaderFlags |= FLAG_CLOSED; /* This indicates the BundleLoader is destroyed */
+ }
+
+ /**
+ * This method loads a class from the bundle. The class is searched for in the
+ * same manner as it would if it was being loaded from a bundle (i.e. all
+ * hosts, fragments, import, required bundles and local resources are searched.
+ *
+ * @param name the name of the desired Class.
+ * @return the resulting Class
+ * @exception java.lang.ClassNotFoundException if the class definition was not found.
+ */
+ final public Class<?> loadClass(String name) throws ClassNotFoundException {
+ BundleClassLoader bcl = createClassLoader();
+ // The instanceof check here is just to be safe. The javadoc contract stated in BundleClassLoader
+ // mandate that BundleClassLoaders be an instance of ClassLoader.
+ if (name.length() > 0 && name.charAt(0) == '[' && bcl instanceof ClassLoader)
+ return Class.forName(name, false, (ClassLoader) bcl);
+ return bcl.loadClass(name);
+ }
+
+ /**
+ * This method gets a resource from the bundle. The resource is searched
+ * for in the same manner as it would if it was being loaded from a bundle
+ * (i.e. all hosts, fragments, import, required bundles and
+ * local resources are searched).
+ *
+ * @param name the name of the desired resource.
+ * @return the resulting resource URL or null if it does not exist.
+ */
+ final URL getResource(String name) {
+ return createClassLoader().getResource(name);
+ }
+
+ public final synchronized ClassLoader getParentClassLoader() {
+ if (parent != null)
+ return parent;
+ createClassLoader();
+ return parent;
+ }
+
+ final public synchronized BundleClassLoader createClassLoader() {
+ if (classloader != null)
+ return classloader;
+ String[] classpath;
+ try {
+ classpath = bundle.getBundleData().getClassPath();
+ } catch (BundleException e) {
+ // no classpath
+ classpath = new String[0];
+ bundle.getFramework().publishFrameworkEvent(FrameworkEvent.ERROR, bundle, e);
+ }
+ if (classpath == null) {
+ // no classpath
+ classpath = new String[0];
+ bundle.getFramework().publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.BUNDLE_NO_CLASSPATH_MATCH, BundleException.MANIFEST_ERROR));
+ }
+ BundleClassLoader bcl = createBCLPrevileged(bundle.getProtectionDomain(), classpath);
+ parent = getParentPrivileged(bcl);
+ classloader = bcl;
+ return classloader;
+ }
+
+ /**
+ * Finds a class local to this bundle. Only the classloader for this bundle is searched.
+ * @param name The name of the class to find.
+ * @return The loaded Class or null if the class is not found.
+ * @throws ClassNotFoundException
+ */
+ Class<?> findLocalClass(String name) throws ClassNotFoundException {
+ if (Debug.DEBUG_LOADER)
+ Debug.println("BundleLoader[" + this + "].findLocalClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ try {
+ Class<?> clazz = createClassLoader().findLocalClass(name);
+ if (Debug.DEBUG_LOADER && clazz != null)
+ Debug.println("BundleLoader[" + this + "] found local class " + name); //$NON-NLS-1$ //$NON-NLS-2$
+ return clazz;
+ } catch (ClassNotFoundException e) {
+ if (e instanceof StatusException) {
+ if ((((StatusException) e).getStatusCode() & StatusException.CODE_ERROR) != 0)
+ throw e;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Finds the class for a bundle. This method is used for delegation by the bundle's classloader.
+ */
+ public Class<?> findClass(String name) throws ClassNotFoundException {
+ return findClass(name, true);
+ }
+
+ Class<?> findClass(String name, boolean checkParent) throws ClassNotFoundException {
+ ClassLoader parentCL = getParentClassLoader();
+ if (checkParent && parentCL != null && name.startsWith(JAVA_PACKAGE))
+ // 1) if startsWith "java." delegate to parent and terminate search
+ // we want to throw ClassNotFoundExceptions if a java.* class cannot be loaded from the parent.
+ return parentCL.loadClass(name);
+ return findClassInternal(name, checkParent, parentCL);
+ }
+
+ private Class<?> findClassInternal(String name, boolean checkParent, ClassLoader parentCL) throws ClassNotFoundException {
+ if (Debug.DEBUG_LOADER)
+ Debug.println("BundleLoader[" + this + "].loadBundleClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ String pkgName = getPackageName(name);
+ boolean bootDelegation = false;
+ // follow the OSGi delegation model
+ if (checkParent && parentCL != null && bundle.getFramework().isBootDelegationPackage(pkgName))
+ // 2) if part of the bootdelegation list then delegate to parent and continue of failure
+ try {
+ return parentCL.loadClass(name);
+ } catch (ClassNotFoundException cnfe) {
+ // we want to continue
+ bootDelegation = true;
+ }
+ Class<?> result = null;
+ try {
+ result = (Class<?>) searchHooks(name, PRE_CLASS);
+ } catch (ClassNotFoundException e) {
+ throw e;
+ } catch (FileNotFoundException e) {
+ // will not happen
+ }
+ if (result != null)
+ return result;
+ // 3) search the imported packages
+ PackageSource source = findImportedSource(pkgName, null);
+ if (source != null) {
+ // 3) found import source terminate search at the source
+ result = source.loadClass(name);
+ if (result != null)
+ return result;
+ throw new ClassNotFoundException(name);
+ }
+ // 4) search the required bundles
+ source = findRequiredSource(pkgName, null);
+ if (source != null)
+ // 4) attempt to load from source but continue on failure
+ result = source.loadClass(name);
+ // 5) search the local bundle
+ if (result == null)
+ result = findLocalClass(name);
+ if (result != null)
+ return result;
+ // 6) attempt to find a dynamic import source; only do this if a required source was not found
+ if (source == null) {
+ source = findDynamicSource(pkgName);
+ if (source != null) {
+ result = source.loadClass(name);
+ if (result != null)
+ return result;
+ // must throw CNFE if dynamic import source does not have the class
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ if (result == null)
+ try {
+ result = (Class<?>) searchHooks(name, POST_CLASS);
+ } catch (ClassNotFoundException e) {
+ throw e;
+ } catch (FileNotFoundException e) {
+ // will not happen
+ }
+ // do buddy policy loading
+ if (result == null && policy != null)
+ result = policy.doBuddyClassLoading(name);
+ if (result != null)
+ return result;
+ // hack to support backwards compatibiility for bootdelegation
+ // or last resort; do class context trick to work around VM bugs
+ if (parentCL != null && !bootDelegation && ((checkParent && bundle.getFramework().compatibiltyBootDelegation) || isRequestFromVM()))
+ // we don't need to continue if a CNFE is thrown here.
+ try {
+ return parentCL.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ // we want to generate our own exception below
+ }
+ throw new ClassNotFoundException(name);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <E> E searchHooks(String name, int type) throws ClassNotFoundException, FileNotFoundException {
+ ClassLoaderDelegateHook[] delegateHooks = bundle.getFramework().getDelegateHooks();
+ if (delegateHooks == null)
+ return null;
+ E result = null;
+ for (int i = 0; i < delegateHooks.length && result == null; i++) {
+ switch (type) {
+ case PRE_CLASS :
+ result = (E) delegateHooks[i].preFindClass(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case POST_CLASS :
+ result = (E) delegateHooks[i].postFindClass(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case PRE_RESOURCE :
+ result = (E) delegateHooks[i].preFindResource(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case POST_RESOURCE :
+ result = (E) delegateHooks[i].postFindResource(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case PRE_RESOURCES :
+ result = (E) delegateHooks[i].preFindResources(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case POST_RESOURCES :
+ result = (E) delegateHooks[i].postFindResources(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case PRE_LIBRARY :
+ result = (E) delegateHooks[i].preFindLibrary(name, createClassLoader(), bundle.getBundleData());
+ break;
+ case POST_LIBRARY :
+ result = (E) delegateHooks[i].postFindLibrary(name, createClassLoader(), bundle.getBundleData());
+ break;
+ }
+ }
+ return result;
+ }
+
+ private boolean isRequestFromVM() {
+ if (bundle.getFramework().isBootDelegationPackage("*") || !bundle.getFramework().contextBootDelegation) //$NON-NLS-1$
+ return false;
+ // works around VM bugs that require all classloaders to have access to parent packages
+ Class<?>[] context = CLASS_CONTEXT.getClassContext();
+ if (context == null || context.length < 2)
+ return false;
+ // skip the first class; it is the ClassContext class
+ for (int i = 1; i < context.length; i++)
+ // find the first class in the context which is not BundleLoader or instanceof ClassLoader
+ if (context[i] != BundleLoader.class && !ClassLoader.class.isAssignableFrom(context[i])) {
+ // only find in parent if the class is not "Class" (Class#forName case) or if the class is not loaded with a BundleClassLoader
+ ClassLoader cl = getClassLoader(context[i]);
+ if (cl != FW_CLASSLOADER) { // extra check incase an adaptor adds another class into the stack besides an instance of ClassLoader
+ if (Class.class != context[i] && !(cl instanceof BundleClassLoader))
+ return true;
+ break;
+ }
+ }
+ return false;
+ }
+
+ private static ClassLoader getClassLoader(final Class<?> clazz) {
+ if (System.getSecurityManager() == null)
+ return clazz.getClassLoader();
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return clazz.getClassLoader();
+ }
+ });
+ }
+
+ /**
+ * Finds the resource for a bundle. This method is used for delegation by the bundle's classloader.
+ */
+ public URL findResource(String name) {
+ return findResource(name, true);
+ }
+
+ URL findResource(String name, boolean checkParent) {
+ if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
+ name = name.substring(1); /* remove leading slash before search */
+ String pkgName = getResourcePackageName(name);
+ boolean bootDelegation = false;
+ ClassLoader parentCL = getParentClassLoader();
+ // follow the OSGi delegation model
+ // First check the parent classloader for system resources, if it is a java resource.
+ if (checkParent && parentCL != null) {
+ if (pkgName.startsWith(JAVA_PACKAGE))
+ // 1) if startsWith "java." delegate to parent and terminate search
+ // we never delegate java resource requests past the parent
+ return parentCL.getResource(name);
+ else if (bundle.getFramework().isBootDelegationPackage(pkgName)) {
+ // 2) if part of the bootdelegation list then delegate to parent and continue of failure
+ URL result = parentCL.getResource(name);
+ if (result != null)
+ return result;
+ bootDelegation = true;
+ }
+ }
+
+ URL result = null;
+ try {
+ result = (URL) searchHooks(name, PRE_RESOURCE);
+ } catch (FileNotFoundException e) {
+ return null;
+ } catch (ClassNotFoundException e) {
+ // will not happen
+ }
+ if (result != null)
+ return result;
+ // 3) search the imported packages
+ PackageSource source = findImportedSource(pkgName, null);
+ if (source != null)
+ // 3) found import source terminate search at the source
+ return source.getResource(name);
+ // 4) search the required bundles
+ source = findRequiredSource(pkgName, null);
+ if (source != null)
+ // 4) attempt to load from source but continue on failure
+ result = source.getResource(name);
+ // 5) search the local bundle
+ if (result == null)
+ result = findLocalResource(name);
+ if (result != null)
+ return result;
+ // 6) attempt to find a dynamic import source; only do this if a required source was not found
+ if (source == null) {
+ source = findDynamicSource(pkgName);
+ if (source != null)
+ // must return the result of the dynamic import and do not continue
+ return source.getResource(name);
+ }
+
+ if (result == null)
+ try {
+ result = (URL) searchHooks(name, POST_RESOURCE);
+ } catch (FileNotFoundException e) {
+ return null;
+ } catch (ClassNotFoundException e) {
+ // will not happen
+ }
+ // do buddy policy loading
+ if (result == null && policy != null)
+ result = policy.doBuddyResourceLoading(name);
+ if (result != null)
+ return result;
+ // hack to support backwards compatibiility for bootdelegation
+ // or last resort; do class context trick to work around VM bugs
+ if (parentCL != null && !bootDelegation && ((checkParent && bundle.getFramework().compatibiltyBootDelegation) || isRequestFromVM()))
+ // we don't need to continue if the resource is not found here
+ return parentCL.getResource(name);
+ return result;
+ }
+
+ /**
+ * Finds the resources for a bundle. This method is used for delegation by the bundle's classloader.
+ */
+ public Enumeration<URL> findResources(String name) throws IOException {
+ // do not delegate to parent because ClassLoader#getResources already did and it is final!!
+ if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
+ name = name.substring(1); /* remove leading slash before search */
+ String pkgName = getResourcePackageName(name);
+ Enumeration<URL> result = null;
+ try {
+ result = searchHooks(name, PRE_RESOURCES);
+ } catch (ClassNotFoundException e) {
+ // will not happen
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ if (result != null)
+ return result;
+ // start at step 3 because of the comment above about ClassLoader#getResources
+ // 3) search the imported packages
+ PackageSource source = findImportedSource(pkgName, null);
+ if (source != null)
+ // 3) found import source terminate search at the source
+ return source.getResources(name);
+ // 4) search the required bundles
+ source = findRequiredSource(pkgName, null);
+ if (source != null)
+ // 4) attempt to load from source but continue on failure
+ result = source.getResources(name);
+
+ // 5) search the local bundle
+ // compound the required source results with the local ones
+ Enumeration<URL> localResults = findLocalResources(name);
+ result = compoundEnumerations(result, localResults);
+ // 6) attempt to find a dynamic import source; only do this if a required source was not found
+ if (result == null && source == null) {
+ source = findDynamicSource(pkgName);
+ if (source != null)
+ return source.getResources(name);
+ }
+ if (result == null)
+ try {
+ result = searchHooks(name, POST_RESOURCES);
+ } catch (ClassNotFoundException e) {
+ // will not happen
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ if (policy != null) {
+ Enumeration<URL> buddyResult = policy.doBuddyResourcesLoading(name);
+ result = compoundEnumerations(result, buddyResult);
+ }
+ return result;
+ }
+
+ private boolean isSubPackage(String parentPackage, String subPackage) {
+ String prefix = (parentPackage.length() == 0 || parentPackage.equals(DEFAULT_PACKAGE)) ? "" : parentPackage + '.'; //$NON-NLS-1$
+ return subPackage.startsWith(prefix);
+ }
+
+ public Collection<String> listResources(String path, String filePattern, int options) {
+ String pkgName = getResourcePackageName(path.endsWith("/") ? path : path + '/'); //$NON-NLS-1$
+ if ((path.length() > 1) && (path.charAt(0) == '/')) /* if name has a leading slash */
+ path = path.substring(1); /* remove leading slash before search */
+ boolean subPackages = (options & BundleWiring.LISTRESOURCES_RECURSE) != 0;
+ List<String> packages = new ArrayList<String>();
+ // search imported package names
+ KeyedHashSet importSources = getImportedSources(null);
+ if (importSources != null) {
+ KeyedElement[] imports = importSources.elements();
+ for (KeyedElement keyedElement : imports) {
+ String id = ((PackageSource) keyedElement).getId();
+ if (id.equals(pkgName) || (subPackages && isSubPackage(pkgName, id)))
+ packages.add(id);
+ }
+ }
+
+ // now add package names from required bundles
+ if (requiredBundles != null) {
+ KeyedHashSet visited = new KeyedHashSet(false);
+ visited.add(bundle); // always add ourselves so we do not recurse back to ourselves
+ for (BundleLoaderProxy requiredProxy : requiredBundles) {
+ BundleLoader requiredLoader = requiredProxy.getBundleLoader();
+ requiredLoader.addProvidedPackageNames(requiredProxy.getSymbolicName(), pkgName, packages, subPackages, visited);
+ }
+ }
+
+ boolean localSearch = (options & BundleWiring.LISTRESOURCES_LOCAL) != 0;
+ List<String> result = new ArrayList<String>();
+ Set<String> importedPackages = new HashSet<String>(0);
+ for (String name : packages) {
+ // look for import source
+ PackageSource externalSource = findImportedSource(name, null);
+ if (externalSource != null) {
+ // record this package is imported
+ importedPackages.add(name);
+ } else {
+ // look for require bundle source
+ externalSource = findRequiredSource(name, null);
+ }
+ // only add the content of the external source if this is not a localSearch
+ if (externalSource != null && !localSearch) {
+ String packagePath = name.replace('.', '/');
+ Collection<String> externalResources = externalSource.listResources(packagePath, filePattern);
+ for (String resource : externalResources) {
+ if (!result.contains(resource)) // prevent duplicates; could happen if the package is split or exporter has fragments/multiple jars
+ result.add(resource);
+ }
+ }
+ }
+
+ // now search locally
+ Collection<String> localResources = createClassLoader().listLocalResources(path, filePattern, options);
+ for (String resource : localResources) {
+ String resourcePkg = getResourcePackageName(resource);
+ if (!importedPackages.contains(resourcePkg) && !result.contains(resource))
+ result.add(resource);
+ }
+ return result;
+ }
+
+ /*
+ * This method is used by Bundle.getResources to do proper parent delegation.
+ */
+ public Enumeration<URL> getResources(String name) throws IOException {
+ if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
+ name = name.substring(1); /* remove leading slash before search */
+ String pkgName = getResourcePackageName(name);
+ // follow the OSGi delegation model
+ // First check the parent classloader for system resources, if it is a java resource.
+ Enumeration<URL> result = null;
+ if (pkgName.startsWith(JAVA_PACKAGE) || bundle.getFramework().isBootDelegationPackage(pkgName)) {
+ // 1) if startsWith "java." delegate to parent and terminate search
+ // 2) if part of the bootdelegation list then delegate to parent and continue of failure
+ ClassLoader parentCL = getParentClassLoader();
+ result = parentCL == null ? null : parentCL.getResources(name);
+ if (pkgName.startsWith(JAVA_PACKAGE))
+ return result;
+ }
+ return compoundEnumerations(result, findResources(name));
+ }
+
+ public static <E> Enumeration<E> compoundEnumerations(Enumeration<E> list1, Enumeration<E> list2) {
+ if (list2 == null || !list2.hasMoreElements())
+ return list1;
+ if (list1 == null || !list1.hasMoreElements())
+ return list2;
+ List<E> compoundResults = new ArrayList<E>();
+ while (list1.hasMoreElements())
+ compoundResults.add(list1.nextElement());
+ while (list2.hasMoreElements()) {
+ E item = list2.nextElement();
+ if (!compoundResults.contains(item)) //don't add duplicates
+ compoundResults.add(item);
+ }
+ return Collections.enumeration(compoundResults);
+ }
+
+ /**
+ * Finds a resource local to this bundle. Only the classloader for this bundle is searched.
+ * @param name The name of the resource to find.
+ * @return The URL to the resource or null if the resource is not found.
+ */
+ URL findLocalResource(final String name) {
+ return createClassLoader().findLocalResource(name);
+ }
+
+ /**
+ * Returns an Enumeration of URLs representing all the resources with
+ * the given name. Only the classloader for this bundle is searched.
+ *
+ * @param name the resource name
+ * @return an Enumeration of URLs for the resources
+ */
+ Enumeration<URL> findLocalResources(String name) {
+ return createClassLoader().findLocalResources(name);
+ }
+
+ /**
+ * Returns the absolute path name of a native library.
+ *
+ * @param name the library name
+ * @return the absolute path of the native library or null if not found
+ */
+ public String findLibrary(final String name) {
+ if (System.getSecurityManager() == null)
+ return findLocalLibrary(name);
+ return AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return findLocalLibrary(name);
+ }
+ });
+ }
+
+ final String findLocalLibrary(final String name) {
+ String result = null;
+ try {
+ result = (String) searchHooks(name, PRE_LIBRARY);
+ } catch (FileNotFoundException e) {
+ return null;
+ } catch (ClassNotFoundException e) {
+ // will not happen
+ }
+ if (result != null)
+ return result;
+ result = bundle.getBundleData().findLibrary(name);
+ if (result != null)
+ return result;
+
+ // look in fragments imports ...
+ BundleFragment[] fragments = bundle.getFragments();
+ if (fragments != null)
+ for (int i = 0; i < fragments.length; i++) {
+ result = fragments[i].getBundleData().findLibrary(name);
+ if (result != null)
+ return result;
+ }
+ try {
+ return (String) searchHooks(name, POST_LIBRARY);
+ } catch (FileNotFoundException e) {
+ return null; // this is not necessary; but being consistent in case another step is added below
+ } catch (ClassNotFoundException e) {
+ // will not happen
+ }
+ return null;
+ }
+
+ /*
+ * Return the bundle we are associated with.
+ */
+ public final AbstractBundle getBundle() {
+ return bundle;
+ }
+
+ private BundleClassLoader createBCLPrevileged(final BundleProtectionDomain pd, final String[] cp) {
+ // Create the classloader as previleged code if security manager is present.
+ if (System.getSecurityManager() == null)
+ return createBCL(pd, cp);
+
+ return AccessController.doPrivileged(new PrivilegedAction<BundleClassLoader>() {
+ public BundleClassLoader run() {
+ return createBCL(pd, cp);
+ }
+ });
+
+ }
+
+ BundleClassLoader createBCL(final BundleProtectionDomain pd, final String[] cp) {
+ BundleClassLoader bcl = bundle.getBundleData().createClassLoader(BundleLoader.this, pd, cp);
+ // attach existing fragments to classloader
+ BundleFragment[] fragments = bundle.getFragments();
+ if (fragments != null)
+ for (int i = 0; i < fragments.length; i++) {
+ try {
+ bcl.attachFragment(fragments[i].getBundleData(), fragments[i].getProtectionDomain(), fragments[i].getBundleData().getClassPath());
+ } catch (BundleException be) {
+ bundle.getFramework().publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
+ }
+ }
+
+ // finish the initialization of the classloader.
+ bcl.initialize();
+ return bcl;
+ }
+
+ /**
+ * Return a string representation of this loader.
+ * @return String
+ */
+ public final String toString() {
+ BundleData result = bundle.getBundleData();
+ return result == null ? "BundleLoader.bundledata == null!" : result.toString(); //$NON-NLS-1$
+ }
+
+ /**
+ * Return true if the target package name matches
+ * a name in the DynamicImport-Package manifest header.
+ *
+ * @param pkgname The name of the requested class' package.
+ * @return true if the package should be imported.
+ */
+ private final synchronized boolean isDynamicallyImported(String pkgname) {
+ if (this instanceof SystemBundleLoader)
+ return false; // system bundle cannot dynamically import
+ // must check for startsWith("java.") to satisfy R3 section 4.7.2
+ if (pkgname.startsWith("java.")) //$NON-NLS-1$
+ return true;
+
+ /* quick shortcut check */
+ if ((loaderFlags & FLAG_HASDYNAMICIMPORTS) == 0)
+ return false;
+
+ /* "*" shortcut */
+ if ((loaderFlags & FLAG_HASDYNAMICEIMPORTALL) != 0)
+ return true;
+
+ /* match against specific names */
+ if (dynamicImportPackages != null)
+ for (int i = 0; i < dynamicImportPackages.length; i++)
+ if (pkgname.equals(dynamicImportPackages[i]))
+ return true;
+
+ /* match against names with trailing wildcards */
+ if (dynamicImportPackageStems != null)
+ for (int i = 0; i < dynamicImportPackageStems.length; i++)
+ if (pkgname.startsWith(dynamicImportPackageStems[i]))
+ return true;
+
+ return false;
+ }
+
+ final void addExportedProvidersFor(String symbolicName, String packageName, List<PackageSource> result, KeyedHashSet visited) {
+ if (!visited.add(bundle))
+ return;
+
+ // See if we locally provide the package.
+ PackageSource local = null;
+ if (isExportedPackage(packageName))
+ local = proxy.getPackageSource(packageName);
+ else if (isSubstitutedExport(packageName)) {
+ result.add(findImportedSource(packageName, visited));
+ return; // should not continue to required bundles in this case
+ }
+ // Must search required bundles that are exported first.
+ if (requiredBundles != null) {
+ int size = reexportTable == null ? 0 : reexportTable.length;
+ int reexportIndex = 0;
+ for (int i = 0; i < requiredBundles.length; i++) {
+ if (local != null) {
+ // always add required bundles first if we locally provide the package
+ // This allows a bundle to provide a package from a required bundle without
+ // re-exporting the whole required bundle.
+ requiredBundles[i].getBundleLoader().addExportedProvidersFor(symbolicName, packageName, result, visited);
+ } else if (reexportIndex < size && reexportTable[reexportIndex] == i) {
+ reexportIndex++;
+ requiredBundles[i].getBundleLoader().addExportedProvidersFor(symbolicName, packageName, result, visited);
+ }
+ }
+ }
+
+ // now add the locally provided package.
+ if (local != null && local.isFriend(symbolicName))
+ result.add(local);
+ }
+
+ final void addProvidedPackageNames(String symbolicName, String packageName, List<String> result, boolean subPackages, KeyedHashSet visitied) {
+ if (!visitied.add(bundle))
+ return;
+ for (String exported : exportedPackages) {
+ if (exported.equals(packageName) || (subPackages && isSubPackage(packageName, exported))) {
+ if (!result.contains(exported))
+ result.add(exported);
+ }
+ }
+ if (substitutedPackages != null)
+ for (String substituted : substitutedPackages) {
+ if (substituted.equals(packageName) || (subPackages && isSubPackage(packageName, substituted))) {
+ if (!result.contains(substituted))
+ result.add(substituted);
+ }
+ }
+ if (requiredBundles != null) {
+ int size = reexportTable == null ? 0 : reexportTable.length;
+ int reexportIndex = 0;
+ for (int i = 0; i < requiredBundles.length; i++) {
+ if (reexportIndex < size && reexportTable[reexportIndex] == i) {
+ reexportIndex++;
+ requiredBundles[i].getBundleLoader().addProvidedPackageNames(symbolicName, packageName, result, subPackages, visitied);
+ }
+ }
+ }
+ }
+
+ final boolean isExportedPackage(String name) {
+ return exportedPackages.contains(name);
+ }
+
+ final boolean isSubstitutedExport(String name) {
+ return substitutedPackages == null ? false : substitutedPackages.contains(name);
+ }
+
+ private void addDynamicImportPackage(ImportPackageSpecification[] packages) {
+ if (packages == null)
+ return;
+ List<String> dynamicImports = new ArrayList<String>(packages.length);
+ for (int i = 0; i < packages.length; i++)
+ if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(packages[i].getDirective(Constants.RESOLUTION_DIRECTIVE)))
+ dynamicImports.add(packages[i].getName());
+ if (dynamicImports.size() > 0)
+ addDynamicImportPackage(dynamicImports.toArray(new String[dynamicImports.size()]));
+ }
+
+ /**
+ * Adds a list of DynamicImport-Package manifest elements to the dynamic
+ * import tables of this BundleLoader. Duplicate packages are checked and
+ * not added again. This method is not thread safe. Callers should ensure
+ * synchronization when calling this method.
+ * @param packages the DynamicImport-Package elements to add.
+ */
+ private void addDynamicImportPackage(String[] packages) {
+ if (packages == null)
+ return;
+
+ loaderFlags |= FLAG_HASDYNAMICIMPORTS;
+ int size = packages.length;
+ List<String> stems;
+ if (dynamicImportPackageStems == null) {
+ stems = new ArrayList<String>(size);
+ } else {
+ stems = new ArrayList<String>(size + dynamicImportPackageStems.length);
+ for (int i = 0; i < dynamicImportPackageStems.length; i++) {
+ stems.add(dynamicImportPackageStems[i]);
+ }
+ }
+
+ List<String> names;
+ if (dynamicImportPackages == null) {
+ names = new ArrayList<String>(size);
+ } else {
+ names = new ArrayList<String>(size + dynamicImportPackages.length);
+ for (int i = 0; i < dynamicImportPackages.length; i++) {
+ names.add(dynamicImportPackages[i]);
+ }
+ }
+
+ for (int i = 0; i < size; i++) {
+ String name = packages[i];
+ if (isDynamicallyImported(name))
+ continue;
+ if (name.equals("*")) { /* shortcut *///$NON-NLS-1$
+ loaderFlags |= FLAG_HASDYNAMICEIMPORTALL;
+ return;
+ }
+
+ if (name.endsWith(".*")) //$NON-NLS-1$
+ stems.add(name.substring(0, name.length() - 1));
+ else
+ names.add(name);
+ }
+
+ size = stems.size();
+ if (size > 0)
+ dynamicImportPackageStems = stems.toArray(new String[size]);
+
+ size = names.size();
+ if (size > 0)
+ dynamicImportPackages = names.toArray(new String[size]);
+ }
+
+ /**
+ * Adds a list of DynamicImport-Package manifest elements to the dynamic
+ * import tables of this BundleLoader. Duplicate packages are checked and
+ * not added again.
+ * @param packages the DynamicImport-Package elements to add.
+ */
+ public final synchronized void addDynamicImportPackage(ManifestElement[] packages) {
+ if (packages == null)
+ return;
+ List<String> dynamicImports = new ArrayList<String>(packages.length);
+ List<ImportPackageSpecification> dynamicImportSpecs = new ArrayList<ImportPackageSpecification>(packages.length);
+ for (ManifestElement dynamicImportElement : packages) {
+ String[] names = dynamicImportElement.getValueComponents();
+ for (String name : names)
+ dynamicImports.add(name);
+ StateBuilder.addImportPackages(dynamicImportElement, dynamicImportSpecs, 2, true);
+ }
+ if (dynamicImports.size() > 0) {
+ addDynamicImportPackage(dynamicImports.toArray(new String[dynamicImports.size()]));
+ BundleDescription revision = getLoaderProxy().getBundleDescription();
+ State state = revision.getContainingState();
+ state.addDynamicImportPackages(revision, dynamicImportSpecs.toArray(new ImportPackageSpecification[dynamicImportSpecs.size()]));
+ }
+ }
+
+ synchronized public void attachFragment(BundleFragment fragment) throws BundleException {
+ ExportPackageDescription[] exports = proxy.getBundleDescription().getSelectedExports();
+ if (classloader == null) {
+ initializeExports(exports, exportedPackages);
+ return;
+ }
+ String[] classpath = fragment.getBundleData().getClassPath();
+ if (classpath != null)
+ classloader.attachFragment(fragment.getBundleData(), fragment.getProtectionDomain(), classpath);
+ initializeExports(exports, exportedPackages);
+ }
+
+ /*
+ * Finds a packagesource that is either imported or required from another bundle.
+ * This will not include an local package source
+ */
+ private PackageSource findSource(String pkgName) {
+ if (pkgName == null)
+ return null;
+ PackageSource result = findImportedSource(pkgName, null);
+ if (result != null)
+ return result;
+ // Note that dynamic imports are not checked to avoid aggressive wiring (bug 105779)
+ return findRequiredSource(pkgName, null);
+ }
+
+ private PackageSource findImportedSource(String pkgName, KeyedHashSet visited) {
+ KeyedHashSet imports = getImportedSources(visited);
+ if (imports == null)
+ return null;
+ synchronized (imports) {
+ return (PackageSource) imports.getByKey(pkgName);
+ }
+ }
+
+ private PackageSource findDynamicSource(String pkgName) {
+ if (isDynamicallyImported(pkgName)) {
+ ExportPackageDescription exportPackage = bundle.getFramework().getAdaptor().getState().linkDynamicImport(proxy.getBundleDescription(), pkgName);
+ if (exportPackage != null) {
+ PackageSource source = createExportPackageSource(exportPackage, null);
+ synchronized (this) {
+ if (importedSources == null)
+ importedSources = new KeyedHashSet(false);
+ }
+ synchronized (importedSources) {
+ importedSources.add(source);
+ }
+ return source;
+ }
+ }
+ return null;
+ }
+
+ private PackageSource findRequiredSource(String pkgName, KeyedHashSet visited) {
+ if (requiredBundles == null)
+ return null;
+ synchronized (requiredSources) {
+ PackageSource result = (PackageSource) requiredSources.getByKey(pkgName);
+ if (result != null)
+ return result.isNullSource() ? null : result;
+ }
+ if (visited == null)
+ visited = new KeyedHashSet(false);
+ visited.add(bundle); // always add ourselves so we do not recurse back to ourselves
+ List<PackageSource> result = new ArrayList<PackageSource>(3);
+ for (int i = 0; i < requiredBundles.length; i++) {
+ BundleLoader requiredLoader = requiredBundles[i].getBundleLoader();
+ requiredLoader.addExportedProvidersFor(proxy.getSymbolicName(), pkgName, result, visited);
+ }
+ // found some so cache the result for next time and return
+ PackageSource source;
+ if (result.size() == 0) {
+ // did not find it in our required bundles lets record the failure
+ // so we do not have to do the search again for this package.
+ source = NullPackageSource.getNullPackageSource(pkgName);
+ } else if (result.size() == 1) {
+ // if there is just one source, remember just the single source
+ source = result.get(0);
+ } else {
+ // if there was more than one source, build a multisource and cache that.
+ PackageSource[] srcs = result.toArray(new PackageSource[result.size()]);
+ source = createMultiSource(pkgName, srcs);
+ }
+ synchronized (requiredSources) {
+ requiredSources.add(source);
+ }
+ return source.isNullSource() ? null : source;
+ }
+
+ /*
+ * Gets the package source for the pkgName. This will include the local package source
+ * if the bundle exports the package. This is used to compare the PackageSource of a
+ * package from two different bundles.
+ */
+ public final PackageSource getPackageSource(String pkgName) {
+ PackageSource result = findSource(pkgName);
+ if (!isExportedPackage(pkgName))
+ return result;
+ // if the package is exported then we need to get the local source
+ PackageSource localSource = proxy.getPackageSource(pkgName);
+ if (result == null)
+ return localSource;
+ if (localSource == null)
+ return result;
+ return createMultiSource(pkgName, new PackageSource[] {result, localSource});
+ }
+
+ private ClassLoader getParentPrivileged(final BundleClassLoader bcl) {
+ if (System.getSecurityManager() == null)
+ return bcl.getParent();
+
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return bcl.getParent();
+ }
+ });
+ }
+
+ static final class ClassContext extends SecurityManager {
+ // need to make this method public
+ public Class<?>[] getClassContext() {
+ return super.getClassContext();
+ }
+ }
+
+ static public void closeBundleLoader(BundleLoaderProxy proxy) {
+ if (proxy == null)
+ return;
+ // First close the BundleLoader
+ BundleLoader loader = proxy.getBasicBundleLoader();
+ if (loader != null)
+ loader.close();
+ proxy.setStale();
+ // if proxy is not null then make sure to unset user object
+ // associated with the proxy in the state
+ BundleDescription description = proxy.getBundleDescription();
+ // must set it back to the bundle object; not null
+ // need to make sure the user object is a BundleReference
+ description.setUserObject(proxy.getBundleData());
+ }
+}

Back to the top