blob: 62f591196e3a8e777366874c32a508d434199a97 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.core;
import java.io.IOException;
import java.net.URL;
import java.security.*;
import java.util.*;
import org.eclipse.osgi.framework.adaptor.*;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.*;
/**
* This object is created when the bundle
* loaded at framework launch or bundle install or update.
*
* It represents the loaded state of the bundle.
*
*/
public class BundleLoader implements ClassLoaderDelegate
{
/** Bundle object */
protected BundleHost bundle;
/** The is the BundleClassLoader for the bundle */
protected BundleClassLoader classloader;
/** Single object for permission checks */
protected BundleResourcePermission resourcePermission;
/**
* Hashtable of imported packages. Key is packagename, Value is BundleLoader
*/
protected KeyedHashSet importedPackages;
protected boolean hasImportedPackages = false;
protected boolean hasDynamicImports = false;
/**
* If true, import all packages dynamically.
*/
protected boolean dynamicImportPackageAll;
/**
* If not null, list of package stems to import dynamically.
*/
protected String[] dynamicImportPackageStems;
/**
* If not null, list of package names to import dynamically.
*/
protected String[] dynamicImportPackages;
protected KeyedHashSet providedPackages;
protected KeyedHashSet requiredPackagesCache;
protected BundleLoaderProxy[] requiredBundles;
protected int[] reexportTable;
/**
* 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.
*/
protected 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 null;
}
/**
* 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.
*/
protected 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 null;
}
/**
* Bundle runtime constructor. This object is created when the bundle is
* loaded at framework launch or bundle install or update.
*
* @param bundle Bundle object for this loader.
* @param file BundleFile for this object
* @param manifest Bundle's manifest
* @exception org.osgi.framework.BundleException
*/
protected BundleLoader(BundleHost bundle, org.eclipse.osgi.service.resolver.BundleDescription description) throws BundleException {
this.bundle = bundle;
try {
bundle.getBundleData().open(); /* make sure the BundleData is open */
} catch (IOException e) {
throw new BundleException(Msg.formatter.getString("BUNDLE_READ_EXCEPTION"), e);
}
initialize(description);
}
protected void initialize(BundleDescription description) {
hasImportedPackages = hasDynamicImports = SystemBundleLoader.getSystemPackages() != null;
//This is the fastest way to access to the description for fragments since the hostdescription.getFragments() is slow
org.osgi.framework.Bundle[] fragmentObjects = bundle.getFragments();
BundleDescription[] fragments = new BundleDescription[fragmentObjects==null ? 0 : fragmentObjects.length];
for (int i = 0; i < fragments.length; i++) {
fragments[i] = ((Bundle) fragmentObjects[i]).getBundleDescription();
}
// init the imported packages list taking the bundle...
addImportedPackages(description.getPackages());
// ...and its fragments
for (int i = 0; i < fragments.length; i++)
if (fragments[i].isResolved())
addImportedPackages(fragments[i].getPackages());
// init the require bundles list. Need to account for optional bundles so bundles with
// no supplier should be skipped.
BundleSpecification[] required = description.getRequiredBundles();
ArrayList bundles = new ArrayList(Arrays.asList(required == null ? new BundleSpecification[0] : required));
for (int i = 0; i < fragments.length; i++)
if (fragments[i].isResolved()) {
BundleSpecification[] fragmentRequires = fragments[i].getRequiredBundles();
if (fragmentRequires != null)
bundles.addAll(Arrays.asList(fragmentRequires));
}
if (bundles.size() > 0) {
ArrayList bound = new ArrayList(bundles.size());
int[] reexported = new int[bundles.size()];
int reexportIndex = 0;
for (int i = 0; i < bundles.size(); i++) {
BundleSpecification spec = (BundleSpecification)bundles.get(i);
if (spec.isResolved()) {
String bundleKey = new StringBuffer(spec.getName()).append("_").append(spec.getActualVersion().toString()).toString();
BundleLoaderProxy loaderProxy =
(BundleLoaderProxy) bundle.framework.packageAdmin.exportedBundles.getByKey(bundleKey);
if (loaderProxy != null) {
bound.add(loaderProxy);
if (spec.isExported())
reexported[reexportIndex++] = i;
} else {
if (!spec.isOptional())
// TODO log error
System.out.println("Could not find loaderProxy: " + bundleKey);
}
}
}
requiredBundles = (BundleLoaderProxy[])bound.toArray(new BundleLoaderProxy[bound.size()]);
if (reexportIndex > 0) {
reexportTable = new int[reexportIndex];
System.arraycopy(reexported, 0, reexportTable, 0, reexportIndex);
}
}
// init the provided packages
String[] provides = description.getProvidedPackages();
ArrayList packages = new ArrayList(Arrays.asList(required == null ? new String[0] : provides));
for (int i = 0; i < fragments.length; i++)
if (fragments[i].isResolved()) {
String[] fragmentProvides = fragments[i].getProvidedPackages();
if (fragmentProvides != null)
packages.addAll(Arrays.asList(fragmentProvides));
}
if (packages.size() > 0) {
providedPackages = new KeyedHashSet(packages.size());
for (int i = 0; i < packages.size(); i++)
providedPackages.add(new SingleSourcePackage((String)packages.get(i), bundle.getLoaderProxy()));
}
// init the dynamic imports tables
try {
String spec = bundle.getBundleData().getDynamicImports();
ManifestElement[] imports = ManifestElement.parsePackageDescription(spec);
initDynamicImportPackage(imports);
} catch (BundleException e) {
// TODO log an error
}
}
private void addImportedPackages(PackageSpecification[] packages) {
if (packages != null && packages.length > 0) {
if (!hasImportedPackages || importedPackages == null) {
hasImportedPackages = true;
importedPackages = new KeyedHashSet();
}
for (int i = 0; i < packages.length; i++) {
SingleSourcePackage packagesource =
(SingleSourcePackage) bundle.framework.packageAdmin.exportedPackages.getByKey(packages[i].getName());
if (packagesource != null) {
importedPackages.add(packagesource);
}
}
}
}
protected BundleHost getSupplier(VersionConstraint spec) {
BundleDescription supplier = spec.getSupplier();
if (supplier == null)
return null;
return (BundleHost)bundle.framework.getBundle(supplier.getBundleId());
}
/**
* Close the the Bundle's file.
*
*/
protected void close() {
if (bundle == null)
return;
BundleData bundleData = bundle.getBundleData();
importedPackages = null;
if (bundleData != null) {
if (classloader != null)
classloader.close();
classloader = null;
/* close the jar file */
try {
bundleData.close();
} catch (IOException e) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("IOException on close :" + e.getMessage());
}
bundle = null; /* 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.
*/
protected Class loadClass(String name) throws ClassNotFoundException {
return createClassLoader().loadClass(name, false);
}
/**
* Gets a ResourceBundle using the bundle's classloader.
* @param name The name of the ResourceBundle to get.
* @param locale The locale to use to get the ResourceBundle.
* @return The ResourceBundle.
* @throws java.util.MissingResourceException if the resource is not found.
*/
protected ResourceBundle getResourceBundle(String name, Locale locale){
return ResourceBundle.getBundle(name, locale, createClassLoader());
}
/**
* Imports a class from this Bundle Loader. The local
* classloader is searched then the fragments.
* @param name The name of the class to import.
* @return The loaded Class or null if the class is not found.
*/
protected Class importClass(String name) {
Class result = findLocalClass(name);
return result;
}
protected BundleClassLoader createClassLoader() {
if (classloader != null)
return classloader;
synchronized(this) {
if (classloader != null)
return classloader;
try {
String[] classpath = getClassPath(bundle, System.getProperties());
if (classpath != null){
classloader = createBCLPrevileged(bundle.getProtectionDomain(), classpath);
org.osgi.framework.Bundle[] fragments = bundle.getFragments();
if (fragments != null)
for (int i = 0; i < fragments.length; i++) {
Bundle fragment = (Bundle)fragments[i];
classloader.attachFragment(fragment.getBundleData(), fragment.domain, getClassPath(fragment, System.getProperties()));
}
classloader.initialize();
}
else {
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("BUNDLE_NO_CLASSPATH_MATCH")));
}
} catch (BundleException e) {
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle,e);
}
}
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.
*/
protected Class findLocalClass(String name) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("BundleLoader["+this+"].findLocalClass("+name+")");
try {
Class clazz = createClassLoader().findLocalClass(name);
if (Debug.DEBUG && Debug.DEBUG_LOADER && clazz != null)
Debug.println("BundleLoader[" + this + "] found local class " + name);
return clazz;
} catch (ClassNotFoundException 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 {
if (isClosed())
throw new ClassNotFoundException(name);
if (Debug.DEBUG && Debug.DEBUG_LOADER) {
Debug.println("BundleLoader["+this+"].loadBundleClass("+name+")");
}
String packageName = getPackageName(name);
Class result = null;
if (packageName != null) {
result = findImportedClass(name, packageName);
if (result == null) {
result = findRequiredClass(name, packageName);
}
}
if (result==null) {
result = findLocalClass(name);
if (result==null) {
throw new ClassNotFoundException(name);
}
}
return result;
}
boolean isClosed() {
return bundle == null;
}
/**
* Finds the resource for a bundle. This method is used for delegation by the bundle's classloader.
*/
public URL findResource(String name) {
if (isClosed())
return null;
if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
name = name.substring(1); /* remove leading slash before search */
try {
checkResourcePermission();
} catch (SecurityException e) {
try {
bundle.framework.checkAdminPermission();
} catch (SecurityException ee) {
return null;
}
}
String packageName = getResourcePackageName(name);
URL resource = null;
if (packageName != null) {
resource = findImportedResource(name, packageName);
if (resource == null) {
resource = findRequiredResource(name, packageName);
}
}
if (resource == null) {
resource = findLocalResource(name);
}
return resource;
}
/**
* Finds the resources for a bundle. This method is used for delegation by the bundle's classloader.
*/
public Enumeration findResources(String name) throws IOException {
if (isClosed())
return null;
if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
name = name.substring(1); /* remove leading slash before search */
try {
checkResourcePermission();
} catch (SecurityException e) {
try {
bundle.framework.checkAdminPermission();
} catch (SecurityException ee) {
return null;
}
}
String packageName = getResourcePackageName(name);
Enumeration result = null;
if (packageName != null) {
result = findImportedResources(name, packageName);
if (result == null) {
result = findRequiredResources(name, packageName);
}
}
if (result == null) {
result = findLocalResources(name);
}
return result;
}
/**
* Imports a resource from this Bundle Loader. The local
* classloader is searched then the fragments.
* @param name The name of the resource to import.
* @return The URL to the resource or null if the resource is not found.
*/
protected URL importResource(String name) {
URL result = findLocalResource(name);
return result;
}
/**
* 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.
*/
protected URL findLocalResource(final String name) {
if (System.getSecurityManager() == null)
return createClassLoader().findLocalResource(name);
return (URL) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return createClassLoader().findLocalResource(name);
}
});
}
/**
* Imports the resources from this Bundle Loader. The local
* classloader is searched then the fragments.
* @param name The name of the resource to import.
* @return an Enumeration of URLs for the resources or null if the resource is not found.
*/
protected Enumeration importResources(String name) {
Enumeration result = findLocalResources(name);
return result;
}
/**
* 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
* @throws IOException if I/O errors occur
*/
protected Enumeration findLocalResources(String name) {
if ((name.length() > 1) && (name.charAt(0) == '/')) /* if name has a leading slash */
name = name.substring(1);
try {
checkResourcePermission();
} catch (SecurityException e) {
return null;
}
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 (isClosed())
return null;
if (System.getSecurityManager() == null)
return findLocalLibrary(name);
return (String) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return findLocalLibrary(name);
}
});
}
protected String findLocalLibrary(final String name) {
String result = bundle.getBundleData().findLibrary(name);
if (result != null)
return result;
org.osgi.framework.Bundle[] fragments = bundle.getFragments();
if (fragments == null || fragments.length == 0)
return null;
// look in fragments imports ...
for (int i=0; i<fragments.length; i++) {
result = ((Bundle)fragments[i]).getBundleData().findLibrary(name);
if (result !=null)
return result;
}
return result;
}
/**
* Return the bundle we are associated with.
*
*/
protected Bundle getBundle() {
return bundle;
}
private BundleClassLoader createBCLPrevileged(final ProtectionDomain pd, final String[] cp){
if (System.getSecurityManager() == null)
return bundle.getBundleData().createClassLoader(BundleLoader.this,pd,cp);
return (BundleClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return bundle.getBundleData().createClassLoader(BundleLoader.this,pd,cp);
}
});
}
/**
* Check for PackagePermission to Export.
*
* @return true if bundle has the package permission.
*/
protected boolean hasExportPackagePermission(String name) {
ProtectionDomain domain = bundle.getProtectionDomain();
if (domain != null)
return domain.implies(new PackagePermission(name, PackagePermission.EXPORT));
return true;
}
/**
* Check for BundlePermission to Provide.
*
* @return true if bundle has the permission to export the bundle.
*/
protected boolean hasProvideBundlePermission(String uniqueId) {
ProtectionDomain domain = bundle.getProtectionDomain();
if (domain != null)
return domain.implies(new BundlePermission(uniqueId, BundlePermission.PROVIDE));
return true;
}
/**
* Check for PackagePermission to Import.
*
* @return true if bundle has the package permission.
*/
protected boolean hasImportPackagePermission(String name) {
ProtectionDomain domain = bundle.getProtectionDomain();
if (domain != null)
return domain.implies(new PackagePermission(name, PackagePermission.IMPORT));
return true;
}
/**
* Check for BundlePermission to Require.
*
* @return true if bundle has the require permission.
*/
protected boolean hasRequireBundlePermission(String uniqueId) {
ProtectionDomain domain = bundle.getProtectionDomain();
if (domain != null)
return domain.implies(new BundlePermission(uniqueId, BundlePermission.REQUIRE));
return true;
}
/**
* Check for BundlePermission to Host.
*
* @return true if bundle has the require permission.
*/
protected boolean hasHostBundlePermission(String uniqueId) {
ProtectionDomain domain = bundle.getProtectionDomain();
if (domain != null)
return domain.implies(new BundlePermission(uniqueId, BundlePermission.HOST));
return true;
}
/**
* Return a string representation of this loader.
*
* @return String
*/
public String toString() {
BundleData result = bundle.getBundleData();
return result == null ? "BundleLoader.bundledata == null!" : result.toString();
}
protected void checkResourcePermission() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (resourcePermission == null)
resourcePermission = new BundleResourcePermission(bundle.getBundleId());
sm.checkPermission(resourcePermission);
}
}
/**
* Get the BundleLoader for the package if it is imported.
*
* @param pkgname The name of the package to import.
* @return BundleLoader to load from or null if the package is not imported.
*/
protected BundleLoader getPackageExporter(String pkgname) {
if (importedPackages != null) {
PackageSource exporter = (PackageSource)importedPackages.getByKey(pkgname);
if (exporter != null)
return exporter.getSupplier().getBundleLoader();
}
if (isDynamicallyImported(pkgname)) {
PackageSource exporter =
(PackageSource) bundle.framework.packageAdmin.exportedPackages.getByKey(pkgname);
if (exporter != null) {
exporter.getSupplier().markUsed(bundle.getLoaderProxy());
importedPackages.add(exporter);
return exporter.getSupplier().getBundleLoader();
}
}
return null;
}
/**
* 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.
*/
protected boolean isDynamicallyImported(String pkgname)
{
/* quick shortcut check */
if (!hasDynamicImports) {
return false;
}
/* "*" shortcut */
if (dynamicImportPackageAll)
return true;
/*
* If including the system bundle packages by default, dynamically import them.
* Most OSGi framework implementations assume the system bundle packages
* are on the VM classpath. As a result some bundles neglect to import
* framework packages (e.g. org.osgi.framework).
*/
String[] systemPackages = SystemBundleLoader.getSystemPackages();
if (systemPackages != null) {
for (int i = 0; i < systemPackages.length; i++)
if (pkgname.equals(systemPackages[i]))
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;
}
/**
* Find a class using the imported packages for this bundle. Only the
* ImportClassLoader is used for the search.
* @param name The name of the class to find.
* @return The loaded class or null if the class does not belong to a package
* that is imported by the bundle.
* @throws ImportClassNotFoundException If the class does belong to a package
* that is imported by the bundle but the class is not found.
*/
protected Class findImportedClass(String name, String packageName) throws ImportClassNotFoundException {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+this+"].findImportedClass("+name+")");
if (!hasImportedPackages)
return null;
Class result = null;
try {
BundleLoader exporter = getPackageExporter(packageName);
if (exporter != null) {
result = exporter.importClass(name);
if (result == null)
throw new ImportClassNotFoundException(name);
}
} finally {
if (result == null) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader[" + this + "] class "+name+" not found in imported package " + packageName);
} else {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("BundleLoader["+this+"] found imported class "+name);
}
}
return result;
}
protected void addExportedProvidersFor(String packageName, ArrayList result, KeyedHashSet visited) {
// TODO is it ok to use bundle as the visit token or should it be the loader?
if (!visited.add(bundle))
return;
// 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 (reexportIndex < size && reexportTable[reexportIndex] == i) {
reexportIndex++;
requiredBundles[i].getBundleLoader().addExportedProvidersFor(packageName, result, visited);
}
}
}
// now look locally.
PackageSource local = getProvidedPackage(packageName);
if (local != null)
result.add(local.getSupplier());
}
/**
* Find a class using the required bundles for this bundle. Only the
* required bundles are used to search for the class.
* @param name The name of the class to find.
* @return The loaded class or null if the class is not found.
*/
protected PackageSource getProvidersFor(String packageName) {
// first look in the required packages cache
if (requiredPackagesCache != null) {
PackageSource result = (PackageSource)requiredPackagesCache.getByKey(packageName);
if (result != null){
if (result.isNullSource()) {
return null;
}
else {
return result;
}
}
}
// didn't find it in the cache search the actual required bundles
if (requiredBundles == null)
return null;
KeyedHashSet visited = new KeyedHashSet(false);
ArrayList result = new ArrayList(3);
for (int i = 0; i < requiredBundles.length; i++) {
BundleLoader requiredLoader = requiredBundles[i].getBundleLoader();
requiredLoader.addExportedProvidersFor(packageName, result, visited);
}
// found some so cache the result for next time and return
if (requiredPackagesCache == null)
requiredPackagesCache = new KeyedHashSet();
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.
requiredPackagesCache.add(new NullPackageSource(packageName));
return null;
}
else if (result.size() == 1) {
// if there is just one source, remember just the single source
BundleLoaderProxy bundle = (BundleLoaderProxy)result.get(0);
PackageSource source = new SingleSourcePackage(packageName, bundle);
requiredPackagesCache.add(source);
return source;
} else {
// if there was more than one source, build a multisource and cache that.
BundleLoaderProxy[] bundles = (BundleLoaderProxy[])result.toArray(new BundleLoaderProxy[result.size()]);
MultiSourcePackage source = new MultiSourcePackage(packageName, bundles);
requiredPackagesCache.add(source);
return source;
}
}
/**
* Find a class using the required bundles for this bundle. Only the
* required bundles are used to search for the class.
* @param name The name of the class to find.
* @return The loaded class or null if the class is not found.
*/
protected Class findRequiredClass(String name, String packageName) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+this+"].findRequiredClass("+name+")");
PackageSource source = getProvidersFor(packageName);
if (source == null)
return null;
if (source.isMultivalued()) {
BundleLoaderProxy[] bundles = source.getSuppliers();
for (int i = 0; i < bundles.length; i++) {
Class result = bundles[i].getBundleLoader().importClass(name);
if (result != null)
return result;
}
} else
return source.getSupplier().getBundleLoader().importClass(name);
return null;
}
protected PackageSource getProvidedPackage(String name) {
return providedPackages == null ? null : (PackageSource)providedPackages.getByKey(name);
}
/**
* Find a resource using the imported packages for this bundle. Only the
* ImportClassLoader is used for the search.
* @param name The name of the resource to find.
* @return The URL of the resource or null if the resource does not belong to a package
* that is imported by the bundle.
* @throws ImportResourceNotFoundException If the resource does belong to a package
* that is imported by the bundle but the resource is not found.
*/
protected URL findImportedResource(String name, String packageName) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+this+"].findImportedResource("+name+")");
if (!hasImportedPackages)
return null;
BundleLoader exporter = getPackageExporter(packageName);
if (exporter != null) {
URL url = exporter.importResource(name);
if (url != null)
return url;
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+this+"] resource "+name+" not found in imported package "+ packageName);
throw new ImportResourceNotFoundException(name);
}
return null;
}
/**
* Find a resource using the required bundles for this bundle. Only the
* required bundles are used to search.
* @param name The name of the resource to find.
* @return The URL for the resource or null if the resource is not found.
*/
protected URL findRequiredResource(String name, String packageName) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+ this +"].findRequiredResource("+name+")");
PackageSource source = getProvidersFor(packageName);
if (source == null)
return null;
if (source.isMultivalued()) {
BundleLoaderProxy[] bundles = source.getSuppliers();
for (int i = 0; i < bundles.length; i++) {
URL result = bundles[i].getBundleLoader().importResource(name);
if (result != null)
return result;
}
} else
return source.getSupplier().getBundleLoader().importResource(name);
return null;
}
/**
* Returns an Enumeration of URLs representing all the resources with
* the given name.
*
* If the resource is in a package that is imported, call the exporting
* bundle. Otherwise return null.
*
* @param name the resource name
* @return an Enumeration of URLs for the resources if the package is
* imported, null otherwise.
* @throws IOException if I/O errors occur
*/
protected Enumeration findImportedResources(String name, String packageName) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+this+"].findImportedResources("+name+")");
if (!hasImportedPackages)
return null;
BundleLoader exporter = getPackageExporter(packageName);
if (exporter != null)
return exporter.importResources(name);
return null;
}
/**
* Returns an Enumeration of URLs representing all the resources with
* the given name.
* Find the resources using the required bundles for this bundle. Only the
* required bundles are used to search.
*
* If the resource is in a package that is imported, call the exporting
* bundle. Otherwise return null.
*
* @param name the resource name
* @return an Enumeration of URLs for the resources if the package is
* imported, null otherwise.
* @throws IOException if I/O errors occur
*/
protected Enumeration findRequiredResources(String name, String packageName) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println("ImportClassLoader["+this+"].findRequiredResources("+name+")");
PackageSource source = getProvidersFor(packageName);
if (source == null)
return null;
if (source.isMultivalued()) {
BundleLoaderProxy[] bundles = source.getSuppliers();
for (int i = 0; i < bundles.length; i++) {
Enumeration result = bundles[i].getBundleLoader().importResources(name);
if (result != null)
return result;
}
} else
return source.getSupplier().getBundleLoader().importResources(name);
return null;
}
protected void initDynamicImportPackage(ManifestElement[] packages) {
if (packages == null && SystemBundleLoader.getSystemPackages() == null)
return;
hasDynamicImports = hasImportedPackages = true;
// make sure importedPackages is not null;
if (importedPackages == null) {
importedPackages = new KeyedHashSet();
}
if (packages == null)
return;
int size = packages.length;
ArrayList stems = new ArrayList(size);
ArrayList names = new ArrayList(size);
for (int i = 0; i < size; i++) {
String name = packages[i].getValue();
if (name.equals("*")) { /* shortcut */
dynamicImportPackageAll = true;
return;
}
if (name.endsWith(".*"))
stems.add(name.substring(1, name.length()-1));
else
names.add(name);
}
size = stems.size();
if (size > 0)
dynamicImportPackageStems = (String[]) stems.toArray(new String[size]);
size = names.size();
if (size > 0)
dynamicImportPackages = (String[]) names.toArray(new String[size]);
}
protected void clear() {
providedPackages = null;
requiredBundles = null;
importedPackages = null;
dynamicImportPackages = null;
dynamicImportPackageStems = null;
}
protected ClassLoader getClassLoader() {
return classloader;
}
protected void attachFragment(BundleFragment fragment, Properties props){
initialize(bundle.getBundleDescription());
if (classloader == null)
return;
try {
String[] classpath = getClassPath(fragment, props);
if (classpath != null)
classloader.attachFragment(fragment.getBundleData(), fragment.domain, classpath);
else
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, new BundleException(Msg.formatter.getString("BUNDLE_NO_CLASSPATH_MATCH")));
} catch (BundleException e) {
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle,e);
}
}
protected String[] getClassPath(Bundle bundle, Properties props) throws BundleException {
String spec = bundle.getBundleData().getClassPath();
ManifestElement[] classpathElements = ManifestElement.parseClassPath(spec);
return matchClassPath(classpathElements, props);
}
protected String[] matchClassPath(ManifestElement[] classpath, Properties props) {
if (classpath == null) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println(" no classpath");
/* create default BundleClassPath */
return new String[] { "." };
}
ArrayList result = new ArrayList(10);
for (int i = 0; i < classpath.length; i++) {
Filter filter = createFilter(classpath[i].getAttribute("filter"));
if (filter == null || filter.match(props)) {
if (Debug.DEBUG && Debug.DEBUG_LOADER)
Debug.println(" found match for classpath entry " + classpath[i].getValue());
result.add(classpath[i].getValue());
}
}
return (String[]) result.toArray(new String[result.size()]);
}
protected Filter createFilter(String filter) {
if (filter == null)
return null;
try {
return new Filter(filter);
} catch (InvalidSyntaxException e) {
bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR,bundle,e);
return null;
}
}
}