Merged sandbox/rickhall/framework-branch changes r370894:374616 into trunk.
These changes represent a refactoring of the Module Loader layer to provide
better abstractions for modules and search policy to more cleanly support
some R4 features, like Bundle.getEntry(), and future experimental features.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@374660 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
index 4613fd4..b613648 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
@@ -156,7 +156,7 @@
}
catch (InvalidSyntaxException ex)
{
- m_felix.getLogger().log(LogWrapper.LOG_ERROR, "BundleContextImpl: " + ex);
+ m_felix.getLogger().log(Logger.LOG_ERROR, "BundleContextImpl: " + ex);
}
return null;
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java
index 2ab1823..1d059a5 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,14 +19,14 @@
import java.util.Map;
import org.apache.felix.framework.cache.BundleArchive;
-import org.apache.felix.moduleloader.Module;
+import org.apache.felix.moduleloader.IModule;
import org.osgi.framework.*;
class BundleInfo
{
- private LogWrapper m_logger = null;
+ private Logger m_logger = null;
private BundleArchive m_archive = null;
- private Module[] m_modules = null;
+ private IModule[] m_modules = null;
private int m_state = 0;
private long m_modified = 0;
private BundleActivator m_activator = null;
@@ -39,12 +39,12 @@
private int m_lockCount = 0;
private Thread m_lockThread = null;
- protected BundleInfo(LogWrapper logger, BundleArchive archive, Module module)
+ protected BundleInfo(Logger logger, BundleArchive archive, IModule module)
throws Exception
{
m_logger = logger;
m_archive = archive;
- m_modules = (module == null) ? new Module[0] : new Module[] { module };
+ m_modules = (module == null) ? new IModule[0] : new IModule[] { module };
m_state = Bundle.INSTALLED;
m_removalPending = false;
@@ -73,7 +73,7 @@
* no limit on the potential number of bundle JAR file revisions.
* @return array of modules corresponding to the bundle JAR file revisions.
**/
- public Module[] getModules()
+ public IModule[] getModules()
{
return m_modules;
}
@@ -84,7 +84,7 @@
* @return <tt>true</tt> if the specified module is in the array of modules
* associated with this bundle, <tt>false</tt> otherwise.
**/
- public boolean hasModule(Module module)
+ public boolean hasModule(IModule module)
{
for (int i = 0; i < m_modules.length; i++)
{
@@ -101,7 +101,7 @@
* in the module array.
* @return the newest module.
**/
- public Module getCurrentModule()
+ public IModule getCurrentModule()
{
return m_modules[m_modules.length - 1];
}
@@ -111,9 +111,9 @@
* the bundle associated with this <tt>BundleInfo</tt> object.
* @param module the module to add.
**/
- public void addModule(Module module)
+ public void addModule(IModule module)
{
- Module[] dest = new Module[m_modules.length + 1];
+ IModule[] dest = new IModule[m_modules.length + 1];
System.arraycopy(m_modules, 0, dest, 0, m_modules.length);
dest[m_modules.length] = module;
m_modules = dest;
@@ -133,7 +133,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error reading location from bundle archive.",
ex);
return null;
@@ -149,7 +149,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error reading start level from bundle archive.",
ex);
return defaultLevel;
@@ -165,7 +165,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error writing start level to bundle archive.",
ex);
}
@@ -182,7 +182,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error reading manifest from bundle archive.",
ex);
return null;
@@ -218,7 +218,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error reading persistent state from bundle archive.",
ex);
return Bundle.INSTALLED;
@@ -233,7 +233,7 @@
}
catch (Exception ex)
{
- m_logger.log(LogWrapper.LOG_ERROR,
+ m_logger.log(Logger.LOG_ERROR,
"Error writing persistent state to bundle archive.",
ex);
}
@@ -248,7 +248,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error writing persistent state to bundle archive.",
ex);
}
@@ -263,7 +263,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error writing persistent state to bundle archive.",
ex);
}
@@ -342,42 +342,4 @@
m_lockCount = info.m_lockCount;
m_lockThread = info.m_lockThread;
}
-
- /**
- * Converts a module identifier to a bundle identifier. Module IDs
- * are typically <tt><bundle-id>.<revision></tt>; this
- * method returns only the portion corresponding to the bundle ID.
- **/
- protected static long getBundleIdFromModuleId(String id)
- {
- try
- {
- String bundleId = (id.indexOf('.') >= 0)
- ? id.substring(0, id.indexOf('.')) : id;
- return Long.parseLong(bundleId);
- }
- catch (NumberFormatException ex)
- {
- return -1;
- }
- }
-
- /**
- * Converts a module identifier to a bundle identifier. Module IDs
- * are typically <tt><bundle-id>.<revision></tt>; this
- * method returns only the portion corresponding to the revision.
- **/
- protected static int getModuleRevisionFromModuleId(String id)
- {
- try
- {
- String rev = (id.indexOf('.') >= 0)
- ? id.substring(id.indexOf('.') + 1) : id;
- return Integer.parseInt(rev);
- }
- catch (NumberFormatException ex)
- {
- return -1;
- }
- }
}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
index f853fe1..b952a8f 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
*/
package org.apache.felix.framework;
-import org.apache.felix.framework.searchpolicy.R4Version;
import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
import org.osgi.service.packageadmin.ExportedPackage;
class ExportedPackageImpl implements ExportedPackage
@@ -25,12 +25,12 @@
private Felix m_felix = null;
private BundleImpl m_exporter = null;
private String m_name = null;
- private R4Version m_version = null;
+ private Version m_version = null;
private String m_toString = null;
private String m_versionString = null;
public ExportedPackageImpl(
- Felix felix, BundleImpl exporter, String name, R4Version version)
+ Felix felix, BundleImpl exporter, String name, Version version)
{
m_felix = felix;
m_exporter = exporter;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
index cf0b317..cdf8871 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,22 +27,21 @@
import org.apache.felix.framework.util.*;
import org.apache.felix.framework.util.Util;
import org.apache.felix.moduleloader.*;
-import org.apache.felix.moduleloader.search.ResolveException;
-import org.apache.felix.moduleloader.search.ResolveListener;
import org.osgi.framework.*;
import org.osgi.service.packageadmin.ExportedPackage;
public class Felix
{
// Logging related member variables.
- private LogWrapper m_logger = new LogWrapper();
+ private Logger m_logger = new Logger();
// Config properties.
private PropertyResolver m_config = new ConfigImpl();
// Configuration properties passed into constructor.
private MutablePropertyResolver m_configMutable = null;
- // MODULE MANAGER.
- private ModuleManager m_mgr = null;
+ // MODULE FACTORY.
+ private IModuleFactory m_factory = null;
+ private R4SearchPolicyCore m_policyCore = null;
// Object used as a lock when calculating which bundles
// when performing an operation on one or more bundles.
@@ -97,6 +96,9 @@
// Service registry.
private ServiceRegistry m_registry = null;
+ // Reusable bundle URL stream handler.
+ private URLStreamHandler m_bundleStreamHandler = null;
+
// Reusable admin permission object for all instances
// of the BundleImpl.
private static AdminPermission m_adminPerm = new AdminPermission();
@@ -215,7 +217,7 @@
m_frameworkStatus = STARTING_STATUS;
// Initialize member variables.
- m_mgr = null;
+ m_factory = null;
m_configMutable = (configMutable == null)
? new MutablePropertyResolverImpl(new StringMap(false)) : configMutable;
m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
@@ -225,6 +227,7 @@
m_cache = null;
m_nextId = 1L;
m_dispatchQueue = null;
+ m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
m_registry = new ServiceRegistry(m_logger);
// Add a listener to the service registry; this is
@@ -272,18 +275,18 @@
}
// Create search policy for module loader.
- R4SearchPolicy searchPolicy = new R4SearchPolicy(m_logger);
+ m_policyCore = new R4SearchPolicyCore(m_logger);
// Add a resolver listener to the search policy
// so that we will be notified when modules are resolved
// in order to update the bundle state.
- searchPolicy.addResolverListener(new ResolveListener() {
+ m_policyCore.addResolverListener(new ResolveListener() {
public void moduleResolved(ModuleEvent event)
{
BundleImpl bundle = null;
try
{
- long id = BundleInfo.getBundleIdFromModuleId(
+ long id = Util.getBundleIdFromModuleId(
event.getModule().getId());
if (id >= 0)
{
@@ -331,7 +334,8 @@
}
});
- m_mgr = new ModuleManager(searchPolicy, new OSGiURLPolicy(this));
+ m_factory = new ModuleFactoryImpl(m_logger);
+ m_policyCore.setModuleFactory(m_factory);
// Initialize dispatch queue.
m_dispatchQueue = new FelixDispatchQueue(m_logger);
@@ -349,13 +353,16 @@
BundleInfo info = new BundleInfo(
m_logger, new SystemBundleArchive(), null);
systembundle = new SystemBundle(this, info, activatorList);
- systembundle.getInfo().addModule(
- m_mgr.addModule(
- "0", systembundle.getAttributes(),
- systembundle.getResourceSources(),
- systembundle.getLibrarySources(),
- true)); // HACK ALERT! This flag indicates that we will
- // use the parent class loader as a resource source.
+ systembundle.getInfo().addModule(m_factory.createModule("0"));
+ systembundle.getContentLoader().setSearchPolicy(
+ new R4SearchPolicy(
+ m_policyCore, systembundle.getInfo().getCurrentModule()));
+ m_factory.setContentLoader(
+ systembundle.getInfo().getCurrentModule(),
+ systembundle.getContentLoader());
+ m_policyCore.setExports(
+ systembundle.getInfo().getCurrentModule(), systembundle.getExports());
+
m_installedBundleMap.put(
systembundle.getInfo().getLocation(), systembundle);
@@ -363,7 +370,7 @@
// state to be set to RESOLVED.
try
{
- searchPolicy.resolve(systembundle.getInfo().getCurrentModule());
+ m_policyCore.resolve(systembundle.getInfo().getCurrentModule());
}
catch (ResolveException ex)
{
@@ -380,9 +387,9 @@
}
catch (Exception ex)
{
- m_mgr = null;
+ m_factory = null;
DispatchQueue.shutdown();
- m_logger.log(LogWrapper.LOG_ERROR, "Unable to start system bundle.", ex);
+ m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
throw new RuntimeException("Unable to start system bundle.");
}
@@ -397,7 +404,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to list saved bundles: " + ex, ex);
archives = null;
}
@@ -437,14 +444,14 @@
try
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to re-install " + archives[i].getLocation(),
ex);
}
catch (Exception ex2)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to re-install bundle " + archives[i].getId(),
ex);
}
@@ -521,7 +528,7 @@
catch (Exception ex)
{
fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
- m_logger.log(LogWrapper.LOG_ERROR, "Error stopping system bundle.", ex);
+ m_logger.log(Logger.LOG_ERROR, "Error stopping system bundle.", ex);
}
// Loop through all bundles and update any updated bundles.
@@ -538,7 +545,7 @@
catch (Exception ex)
{
fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
- m_logger.log(LogWrapper.LOG_ERROR, "Unable to purge bundle "
+ m_logger.log(Logger.LOG_ERROR, "Unable to purge bundle "
+ bundle.getInfo().getLocation(), ex);
}
}
@@ -556,7 +563,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to remove "
+ m_uninstalledBundles[i].getInfo().getLocation(), ex);
}
@@ -682,7 +689,7 @@
{
fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error starting " + impl.getInfo().getLocation(), th);
}
}
@@ -698,7 +705,7 @@
{
fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error stopping " + impl.getInfo().getLocation(), th);
}
}
@@ -810,7 +817,7 @@
}
catch (BundleException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Unable to acquire lock to set start level.", ex);
+ m_logger.log(Logger.LOG_ERROR, "Unable to acquire lock to set start level.", ex);
return;
}
@@ -847,12 +854,12 @@
catch (Throwable th)
{
rethrow = th;
- m_logger.log(LogWrapper.LOG_ERROR, "Error starting/stopping bundle.", th);
+ m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
}
}
else
{
- m_logger.log(LogWrapper.LOG_WARNING, "Bundle start level must be greater than zero.");
+ m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
}
}
finally
@@ -899,9 +906,18 @@
**/
protected boolean isBundleClass(Class clazz)
{
- if (clazz.getClassLoader() instanceof ModuleClassLoader)
+ if (clazz.getClassLoader() instanceof ContentClassLoader)
{
- return ((ModuleClassLoader) clazz.getClassLoader()).isModuleManagerEqual(m_mgr);
+ IContentLoader contentLoader =
+ ((ContentClassLoader) clazz.getClassLoader()).getContentLoader();
+ IModule[] modules = m_factory.getModules();
+ for (int i = 0; i < modules.length; i++)
+ {
+ if (modules[i].getContentLoader() == contentLoader)
+ {
+ return true;
+ }
+ }
}
return false;
}
@@ -916,13 +932,16 @@
* @return an input stream to the bundle resource.
* @throws IOException if the input stream could not be created.
**/
+/*
+ This might note be needed due to changes in URLHandlersBundleURLConnection
+
protected InputStream getBundleResourceInputStream(URL url)
throws IOException
{
// The URL is constructed like this:
// bundle://<module-id>/<source-idx>/<resource-path>
- Module module = m_mgr.getModule(url.getHost());
+ IModule module = m_factory.getModule(url.getHost());
if (module == null)
{
throw new IOException("Unable to find bundle's module.");
@@ -933,38 +952,22 @@
{
throw new IOException("Unable to find resource: " + url.toString());
}
+
+ // Remove any leading slash.
if (resource.startsWith("/"))
{
resource = resource.substring(1);
}
- int rsIdx = -1;
- try
- {
- rsIdx = Integer.parseInt(resource.substring(0, resource.indexOf("/")));
- }
- catch (NumberFormatException ex)
- {
- new IOException("Error parsing resource index.");
- }
- resource = resource.substring(resource.indexOf("/") + 1);
// Get the resource bytes from the resource source.
- byte[] bytes = null;
- ResourceSource[] resSources = module.getResourceSources();
- if ((resSources != null) && (rsIdx < resSources.length))
- {
- if (resSources[rsIdx].hasResource(resource))
- {
- bytes = resSources[rsIdx].getBytes(resource);
- }
- }
+ byte[] bytes = module.getContentLoader().getResourceBytes(resource);
if (bytes == null)
{
throw new IOException("Unable to find resource: " + url.toString());
}
return new ByteArrayInputStream(bytes);
}
-
+*/
//
// Implementation of Bundle interface methods.
//
@@ -1006,7 +1009,7 @@
{
AccessController.checkPermission(m_adminPerm);
}
- return bundle.getInfo().getCurrentModule().getClassLoader().getResource(name);
+ return bundle.getInfo().getCurrentModule().getContentLoader().getResource(name);
}
protected ServiceReference[] getBundleRegisteredServices(BundleImpl bundle)
@@ -1150,7 +1153,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_WARNING,
+ Logger.LOG_WARNING,
"Exception while evaluating the permission.",
ex);
return false;
@@ -1165,18 +1168,20 @@
**/
protected Class loadBundleClass(BundleImpl bundle, String name) throws ClassNotFoundException
{
- try
+ Class clazz = bundle.getInfo().getCurrentModule().getContentLoader().getClass(name);
+ if (clazz == null)
{
- return bundle.getInfo().getCurrentModule().getClassLoader().loadClass(name);
- }
- catch (ClassNotFoundException ex)
- {
+ // Throw exception.
+ ClassNotFoundException ex = new ClassNotFoundException(name);
+
// The spec says we must fire a framework error.
fireFrameworkEvent(
FrameworkEvent.ERROR, bundle,
new BundleException(ex.getMessage()));
+
throw ex;
}
+ return clazz;
}
/**
@@ -1366,13 +1371,10 @@
// }
}
- // Get the import search policy.
- R4SearchPolicy search = (R4SearchPolicy) m_mgr.getSearchPolicy();
-
- Module module = bundle.getInfo().getCurrentModule();
+ IModule module = bundle.getInfo().getCurrentModule();
try
{
- search.resolve(module);
+ m_policyCore.resolve(module);
}
catch (ResolveException ex)
{
@@ -1380,7 +1382,7 @@
{
throw new BundleException(
"Unresolved package in bundle "
- + BundleInfo.getBundleIdFromModuleId(ex.getModule().getId())
+ + Util.getBundleIdFromModuleId(ex.getModule().getId())
+ ": " + ex.getPackage());
}
else
@@ -1478,7 +1480,7 @@
// Create a module for the new revision; the revision is
// base zero, so subtract one from the revision count to
// get the revision of the new update.
- Module module = createModule(
+ IModule module = createModule(
info.getBundleId(),
archive.getRevisionCount() - 1,
info.getCurrentHeader());
@@ -1487,7 +1489,7 @@
}
catch (Exception ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Unable to update the bundle.", ex);
+ m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
rethrow = ex;
}
@@ -1522,7 +1524,7 @@
}
catch (IOException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Unable to close input stream.", ex);
+ m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
}
}
}
@@ -1614,7 +1616,7 @@
}
catch (Throwable th)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Error stopping bundle.", th);
+ m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
rethrow = th;
}
@@ -1725,7 +1727,7 @@
else
{
m_logger.log(
- LogWrapper.LOG_ERROR, "Unable to remove bundle from installed map!");
+ Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
}
// Set state to uninstalled.
@@ -1846,7 +1848,7 @@
catch (IOException ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to close input stream.", ex);
}
}
@@ -1867,9 +1869,8 @@
}
catch (Exception ex)
{
- ex.printStackTrace();
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Could not purge bundle.", ex);
}
}
@@ -1892,10 +1893,11 @@
catch (Exception ex1)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Could not remove from cache.", ex1);
}
}
+ex.printStackTrace();
throw new BundleException("Could not create bundle object.", ex);
}
@@ -1926,7 +1928,7 @@
catch (IOException ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to close input stream.", ex);
// Not much else we can do.
}
@@ -2367,7 +2369,7 @@
// We do not throw this exception since the bundle
// is not supposed to know about the service at all
// if it does not have permission.
- m_logger.log(LogWrapper.LOG_ERROR, ex.getMessage());
+ m_logger.log(Logger.LOG_ERROR, ex.getMessage());
}
}
@@ -2496,7 +2498,7 @@
}
catch (Exception ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, ex.getMessage());
+ m_logger.log(Logger.LOG_ERROR, ex.getMessage());
return null;
}
}
@@ -2517,14 +2519,13 @@
{
// First, find the bundle exporting the package.
BundleImpl bundle = null;
- R4SearchPolicy search = (R4SearchPolicy) m_mgr.getSearchPolicy();
- Module[] exporters = search.getInUseExporters(new R4Package(pkgName, null, null));
+ IModule[] exporters = m_policyCore.getInUseExporters(new R4Import(pkgName, null, null));
if (exporters != null)
{
// Since OSGi R4 there may be more than one exporting, so just
// take the first one.
bundle = (BundleImpl) getBundle(
- BundleInfo.getBundleIdFromModuleId(exporters[0].getId()));
+ Util.getBundleIdFromModuleId(exporters[0].getId()));
}
// If we have found the exporting bundle, then return the
@@ -2541,13 +2542,13 @@
// that the first module found to be exporting the package is the
// provider of the package, which makes sense since it must have
// been resolved first.
- Module[] modules = bundle.getInfo().getModules();
+ IModule[] modules = bundle.getInfo().getModules();
for (int modIdx = 0; modIdx < modules.length; modIdx++)
{
- R4Package pkg = R4SearchPolicy.getExportPackage(modules[modIdx], pkgName);
- if (pkg != null)
+ R4Export export = Util.getExportPackage(modules[modIdx], pkgName);
+ if (export != null)
{
- return new ExportedPackageImpl(this, bundle, pkgName, pkg.getVersionLow());
+ return new ExportedPackageImpl(this, bundle, pkgName, export.getVersion());
}
}
}
@@ -2619,26 +2620,32 @@
**/
private void getExportedPackages(BundleImpl bundle, List list)
{
- R4SearchPolicy policy = (R4SearchPolicy) m_mgr.getSearchPolicy();
-
// Since a bundle may have many modules associated with it,
// one for each revision in the cache, search each module
// for each revision to get all exports.
- Module[] modules = bundle.getInfo().getModules();
+ IModule[] modules = bundle.getInfo().getModules();
for (int modIdx = 0; modIdx < modules.length; modIdx++)
{
- R4Package[] exports = R4SearchPolicy.getExportsAttr(modules[modIdx]);
- if (exports.length > 0)
+ R4Export[] exports = m_policyCore.getExports(modules[modIdx]);
+ if ((exports != null) && (exports.length > 0))
{
for (int expIdx = 0; expIdx < exports.length; expIdx++)
{
// See if the target bundle's module is one of the
// "in use" exporters of the package.
- Module[] inUseModules = policy.getInUseExporters(exports[expIdx]);
- if (R4SearchPolicy.isModuleInArray(inUseModules, modules[modIdx]))
+ IModule[] inUseModules =
+ m_policyCore.getInUseExporters(
+ new R4Import(exports[expIdx].getName(), null, null));
+ // Search through the current providers to find the target
+ // module.
+ for (int i = 0; (inUseModules != null) && (i < inUseModules.length); i++)
{
- list.add(new ExportedPackageImpl(
- this, bundle, exports[expIdx].getId(), exports[expIdx].getVersionLow()));
+ if (inUseModules[i] == modules[modIdx])
+ {
+ list.add(new ExportedPackageImpl(
+ this, bundle, exports[expIdx].getName(),
+ exports[expIdx].getVersion()));
+ }
}
}
}
@@ -2667,15 +2674,15 @@
if (exporter != importer)
{
// Check the import wires of all modules for all bundles.
- Module[] modules = importer.getInfo().getModules();
+ IModule[] modules = importer.getInfo().getModules();
for (int modIdx = 0; modIdx < modules.length; modIdx++)
{
- R4Wire wire = R4SearchPolicy.getWire(modules[modIdx], ep.getName());
+ R4Wire wire = Util.getWire(modules[modIdx], ep.getName());
// If the resolving module is associated with the
// exporting bundle, then add current bundle to
// import list.
- if ((wire != null) && exporterInfo.hasModule(wire.m_module))
+ if ((wire != null) && exporterInfo.hasModule(wire.getExportingModule()))
{
// Add the bundle to the list of importers.
list.add(bundles[bundleIdx]);
@@ -2808,7 +2815,7 @@
// Create the module for the bundle; although there should only
// ever be one revision at this point, create the module for
// the current revision to be safe.
- Module module = createModule(
+ IModule module = createModule(
archive.getId(), archive.getRevisionCount() - 1, headerMap);
// Finally, create an return the bundle info.
@@ -2824,7 +2831,7 @@
* @param headers The headers map associated with the bundle.
* @return The initialized and/or newly created module.
**/
- private Module createModule(long id, int revision, Map headerMap)
+ private IModule createModule(long id, int revision, Map headerMap)
throws Exception
{
// Get the manifest version.
@@ -2835,31 +2842,14 @@
throw new BundleException("Unknown 'Bundle-ManifestVersion' value: " + version);
}
- // Create the resource sources for the bundle. The resource sources
- // are comprised of the bundle's class path values (as JarResourceSources).
- ResourceSource[] resSources = null;
- try
- {
- // Get bundle class path for the specified revision from cache.
- String[] classPath = m_cache.getArchive(id).getClassPath(revision);
-
- // Create resource sources for everything.
- resSources = new ResourceSource[classPath.length];
- for (int i = 0; i < classPath.length; i++)
- {
- resSources[i] = new JarResourceSource(classPath[i]);
- }
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- throw new BundleException("Error in class path: " + ex);
- }
-
// Get import packages from bundle manifest.
- R4Package[] imports = R4Package.parseImportOrExportHeader(
+ R4Package[] pkgs = R4Package.parseImportOrExportHeader(
(String) headerMap.get(Constants.IMPORT_PACKAGE));
-
+ R4Import[] imports = new R4Import[pkgs.length];
+ for (int i = 0; i < pkgs.length; i++)
+ {
+ imports[i] = new R4Import(pkgs[i]);
+ }
// Check to make sure that R3 bundles have only specified
// the 'specification-version' attribute and no directives.
@@ -2887,8 +2877,13 @@
}
// Get export packages from bundle manifest.
- R4Package[] exports = R4Package.parseImportOrExportHeader(
+ pkgs = R4Package.parseImportOrExportHeader(
(String) headerMap.get(Constants.EXPORT_PACKAGE));
+ R4Export[] exports = new R4Export[pkgs.length];
+ for (int i = 0; i < pkgs.length; i++)
+ {
+ exports[i] = new R4Export(pkgs[i]);
+ }
// Check to make sure that R3 bundles have only specified
// the 'specification-version' attribute and no directives.
@@ -2915,9 +2910,12 @@
}
}
- R4Package[] newImports = new R4Package[imports.length + exports.length];
+ R4Import[] newImports = new R4Import[imports.length + exports.length];
System.arraycopy(imports, 0, newImports, 0, imports.length);
- System.arraycopy(exports, 0, newImports, imports.length, exports.length);
+ for (int i = 0; i < exports.length; i++)
+ {
+ newImports[i + imports.length] = new R4Import(exports[i]);
+ }
imports = newImports;
}
@@ -2933,24 +2931,28 @@
{
usesValue = usesValue
+ ((usesValue.length() > 0) ? "," : "")
- + imports[i].getId();
+ + imports[i].getName();
}
R4Directive uses = new R4Directive(
FelixConstants.USES_DIRECTIVE, usesValue);
for (int i = 0; (exports != null) && (i < exports.length); i++)
{
- exports[i] = new R4Package(
- exports[i].getId(),
+ exports[i] = new R4Export(
+ exports[i].getName(),
new R4Directive[] { uses },
exports[i].getAttributes());
}
}
// TODO: CHECK FOR DUPLICATE IMPORTS/EXPORTS HERE.
-
// Get dynamic import packages from bundle manifest.
- R4Package[] dynamics = R4Package.parseImportOrExportHeader(
+ pkgs = R4Package.parseImportOrExportHeader(
(String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
+ R4Import[] dynamics = new R4Import[pkgs.length];
+ for (int i = 0; i < pkgs.length; i++)
+ {
+ dynamics[i] = new R4Import(pkgs[i]);
+ }
// Check to make sure that R3 bundles have no attributes or
// directives.
@@ -2969,30 +2971,56 @@
}
}
- Object[][] attributes = {
- new Object[] { R4SearchPolicy.EXPORTS_ATTR, exports },
- new Object[] { R4SearchPolicy.IMPORTS_ATTR, imports },
- new Object[] { R4SearchPolicy.DYNAMICIMPORTS_ATTR, dynamics }
- };
-
// Get native library entry names for module library sources.
- LibraryInfo[] libraries =
+ R4LibraryHeader[] libraryHeaders =
Util.parseLibraryStrings(
+ m_logger,
Util.parseDelimitedString(
(String) headerMap.get(Constants.BUNDLE_NATIVECODE), ","));
- LibrarySource[] libSources = {
- new OSGiLibrarySource(
+ R4Library[] libraries = new R4Library[libraryHeaders.length];
+ for (int i = 0; i < libraries.length; i++)
+ {
+ libraries[i] = new R4Library(
m_logger, m_cache, id, revision,
getProperty(Constants.FRAMEWORK_OS_NAME),
getProperty(Constants.FRAMEWORK_PROCESSOR),
- libraries)
- };
+ libraryHeaders[i]);
+ }
- Module module =
- m_mgr.addModule(
- Long.toString(id) + "." + Integer.toString(revision),
- attributes, resSources, libSources);
+ // Now that we have all of the metadata associated with the
+ // module, we need to create the module itself. This is somewhat
+ // complicated because a module is constructed out of several
+ // interrelated pieces (e.g., content loader, search policy,
+ // url policy). We need to create all of these pieces and bind
+ // them together.
+ // First, create the module.
+ IModule module = m_factory.createModule(
+ Long.toString(id) + "." + Integer.toString(revision));
+ // Attach the R4 search policy metadata to the module.
+ m_policyCore.setExports(module, exports);
+ m_policyCore.setImports(module, imports);
+ m_policyCore.setDynamicImports(module, dynamics);
+ m_policyCore.setLibraries(module, libraries);
+
+ // Create the content loader associated with the module archive.
+ IContentLoader contentLoader = new ContentLoaderImpl(
+ m_logger,
+ m_cache.getArchive(id).getContent(revision),
+ m_cache.getArchive(id).getContentPath(revision));
+ // Set the content loader's search policy.
+ contentLoader.setSearchPolicy(
+ new R4SearchPolicy(m_policyCore, module));
+ // Set the content loader's URL policy.
+ contentLoader.setURLPolicy(
+// TODO: FIX - NEED URL POLICY PER MODULE.
+ new URLPolicyImpl(
+ m_logger, m_bundleStreamHandler, module));
+
+ // Set the module's content loader to the created content loader.
+ m_factory.setContentLoader(module, contentLoader);
+
+ // Done, so return the module.
return module;
}
@@ -3013,7 +3041,7 @@
{
activator =
m_cache.getArchive(info.getBundleId())
- .getActivator(info.getCurrentModule().getClassLoader());
+ .getActivator(info.getCurrentModule().getContentLoader());
}
catch (Exception ex)
{
@@ -3037,7 +3065,7 @@
if (className != null)
{
className = className.trim();
- Class clazz = info.getCurrentModule().getClassLoader().loadClass(className);
+ Class clazz = info.getCurrentModule().getContentLoader().getClass(className);
if (clazz == null)
{
throw new BundleException("Not found: "
@@ -3070,10 +3098,10 @@
// way to do this is to remove the bundle, but that
// would be incorrect, because this is a refresh operation
// and should not trigger bundle REMOVE events.
- Module[] modules = info.getModules();
+ IModule[] modules = info.getModules();
for (int i = 0; i < modules.length; i++)
{
- m_mgr.removeModule(modules[i]);
+ m_factory.removeModule(modules[i]);
}
// Purge all bundle revisions, but the current one.
@@ -3094,10 +3122,10 @@
// Remove the bundle's associated modules from
// the module manager.
- Module[] modules = bundle.getInfo().getModules();
+ IModule[] modules = bundle.getInfo().getModules();
for (int i = 0; i < modules.length; i++)
{
- m_mgr.removeModule(modules[i]);
+ m_factory.removeModule(modules[i]);
}
// Remove the bundle from the cache.
@@ -3209,11 +3237,11 @@
System.getProperty("os.version"));
String s = null;
- s = OSGiLibrarySource.normalizePropertyValue(
+ s = R4Library.normalizePropertyValue(
FelixConstants.FRAMEWORK_OS_NAME,
System.getProperty("os.name"));
m_configMutable.put(FelixConstants.FRAMEWORK_OS_NAME, s);
- s = OSGiLibrarySource.normalizePropertyValue(
+ s = R4Library.normalizePropertyValue(
FelixConstants.FRAMEWORK_PROCESSOR,
System.getProperty("os.arch"));
m_configMutable.put(FelixConstants.FRAMEWORK_PROCESSOR, s);
@@ -3243,7 +3271,7 @@
}
catch (NumberFormatException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Invalid property: " + keys[i]);
+ m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
}
StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
if (st.countTokens() > 0)
@@ -3262,7 +3290,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR, "Auto-properties install.", ex);
+ Logger.LOG_ERROR, "Auto-properties install.", ex);
}
}
}
@@ -3289,7 +3317,7 @@
}
catch (NumberFormatException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Invalid property: " + keys[i]);
+ m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
}
StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
if (st.countTokens() > 0)
@@ -3307,7 +3335,7 @@
}
catch (Exception ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "Auto-properties install.", ex);
+ m_logger.log(Logger.LOG_ERROR, "Auto-properties install.", ex);
}
}
}
@@ -3342,7 +3370,7 @@
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR, "Auto-properties start.", ex);
+ Logger.LOG_ERROR, "Auto-properties start.", ex);
}
}
}
@@ -3446,7 +3474,7 @@
// Logging methods and inner classes.
//
- public LogWrapper getLogger()
+ public Logger getLogger()
{
return m_logger;
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/FilterImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/FilterImpl.java
index 280d265..c41aeea 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/FilterImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/FilterImpl.java
@@ -32,7 +32,7 @@
**/
public class FilterImpl implements Filter
{
- private LogWrapper m_logger = null;
+ private Logger m_logger = null;
private String m_toString = null;
private Evaluator m_evaluator = null;
private SimpleMapper m_mapper = null;
@@ -47,7 +47,7 @@
* Construct a filter for a given filter expression string.
* @param expr the filter expression string for the filter.
**/
- public FilterImpl(LogWrapper logger, String expr) throws InvalidSyntaxException
+ public FilterImpl(Logger logger, String expr) throws InvalidSyntaxException
{
m_logger = logger;
if (expr == null)
@@ -132,11 +132,11 @@
}
catch (AttributeNotFoundException ex)
{
- m_logger.log(LogWrapper.LOG_DEBUG, "FilterImpl: " + ex);
+ m_logger.log(Logger.LOG_DEBUG, "FilterImpl: " + ex);
}
catch (EvaluationException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "FilterImpl: " + toString(), ex);
+ m_logger.log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex);
}
return false;
}
@@ -158,11 +158,11 @@
}
catch (AttributeNotFoundException ex)
{
- m_logger.log(LogWrapper.LOG_DEBUG, "FilterImpl: " + ex);
+ m_logger.log(Logger.LOG_DEBUG, "FilterImpl: " + ex);
}
catch (EvaluationException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "FilterImpl: " + toString(), ex);
+ m_logger.log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex);
}
return false;
}
@@ -176,11 +176,11 @@
}
catch (AttributeNotFoundException ex)
{
- m_logger.log(LogWrapper.LOG_DEBUG, "FilterImpl: " + ex);
+ m_logger.log(Logger.LOG_DEBUG, "FilterImpl: " + ex);
}
catch (EvaluationException ex)
{
- m_logger.log(LogWrapper.LOG_ERROR, "FilterImpl: " + toString(), ex); }
+ m_logger.log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex); }
return false;
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/LogWrapper.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Logger.java
similarity index 98%
rename from org.apache.felix.framework/src/main/java/org/apache/felix/framework/LogWrapper.java
rename to org.apache.felix.framework/src/main/java/org/apache/felix/framework/Logger.java
index e128f49..6266c10 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/LogWrapper.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Logger.java
@@ -31,7 +31,7 @@
* </p>
**/
// TODO: Modify LogWrapper to get LogService service object and invoke with reflection.
-public class LogWrapper
+public class Logger
{
public static final int LOG_ERROR = 1;
public static final int LOG_WARNING = 2;
@@ -40,7 +40,7 @@
private Object m_logObj = null;
- public LogWrapper()
+ public Logger()
{
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/OSGiURLPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/OSGiURLPolicy.java
deleted file mode 100644
index 5c9c299..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/OSGiURLPolicy.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework;
-
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedExceptionAction;
-
-import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.moduleloader.*;
-
-public class OSGiURLPolicy implements URLPolicy
-{
- private Felix m_framework = null;
- private URLHandlersBundleStreamHandler m_bundleHandler = null;
- private FakeURLStreamHandler m_fakeHandler = null;
-
- public OSGiURLPolicy(Felix framework)
- {
- m_framework = framework;
- }
-
- public URL createCodeSourceURL(ModuleManager mgr, Module module)
- {
- URL url = null;
-/*
- BundleImpl bundle = null;
- try
- {
- bundle = (BundleImpl)
- m_felix.getBundle(BundleInfo.getBundleIdFromModuleId(module.getId()));
- if (bundle != null)
- {
- url = new URL(bundle.getInfo().getLocation());
- }
- }
- catch (NumberFormatException ex)
- {
- url = null;
- }
- catch (MalformedURLException ex)
- {
- if (m_fakeHandler == null)
- {
- m_fakeHandler = new FakeURLStreamHandler();
- }
- try
- {
- url = new URL(null,
- FelixConstants.FAKE_URL_PROTOCOL_VALUE
- + "//" + bundle.getLocation(), m_fakeHandler);
- }
- catch (Exception ex2)
- {
- url = null;
- }
- }
-*/
- return url;
- }
-
- public URL createResourceURL(ModuleManager mgr, Module module, int rsIdx, String name)
- {
- if (m_bundleHandler == null)
- {
- m_bundleHandler = new URLHandlersBundleStreamHandler(m_framework);
- }
-
- // Add a slash if there is one already, otherwise
- // the is no slash separating the host from the file
- // in the resulting URL.
- if (!name.startsWith("/"))
- {
- name = "/" + name;
- }
-
- try
- {
- if (System.getSecurityManager() != null)
- {
- return (URL) AccessController.doPrivileged(
- new CreateURLPrivileged(module.getId(), rsIdx, name));
- }
- else
- {
- return new URL(FelixConstants.BUNDLE_URL_PROTOCOL,
- module.getId(), -1, "/" + rsIdx + name, m_bundleHandler);
- }
- }
- catch (Exception ex)
- {
- System.err.println("OSGiURLPolicy: " + ex);
- return null;
- }
- }
-
- /**
- * This simple class is used to perform the privileged action of
- * creating a URL using the "bundle:" protocol stream handler.
- **/
- private class CreateURLPrivileged implements PrivilegedExceptionAction
- {
- private String m_id = null;
- private int m_rsIdx = 0;
- private String m_name = null;
-
- public CreateURLPrivileged(String id, int rsIdx, String name)
- {
- m_id = id;
- m_rsIdx = rsIdx;
- m_name = name;
- }
-
- public Object run() throws Exception
- {
- return new URL(FelixConstants.BUNDLE_URL_PROTOCOL,
- m_id, -1, "/" + m_rsIdx + m_name, m_bundleHandler);
- }
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java
index 72c5b7d..3b4eb7c 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
*/
package org.apache.felix.framework;
-import org.apache.felix.framework.searchpolicy.R4SearchPolicy;
import org.apache.felix.framework.searchpolicy.R4Wire;
+import org.apache.felix.framework.util.Util;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
@@ -31,7 +31,7 @@
m_registration = reg;
m_bundle = bundle;
}
-
+
protected ServiceRegistrationImpl getServiceRegistration()
{
return m_registration;
@@ -117,11 +117,12 @@
boolean allow = true;
// Get the package.
String pkgName =
- org.apache.felix.moduleloader.Util.getClassPackage(className);
- // Get package wiring from service provider and requester.
- R4Wire requesterWire = R4SearchPolicy.getWire(
+ Util.getClassPackage(className);
+ // Get package wiring from service requester.
+ R4Wire requesterWire = Util.getWire(
((BundleImpl) requester).getInfo().getCurrentModule(), pkgName);
- R4Wire providerWire = R4SearchPolicy.getWire(
+ // Get package wiring from service provider.
+ R4Wire providerWire = Util.getWire(
((BundleImpl) m_bundle).getInfo().getCurrentModule(), pkgName);
// There are three situations that may occur here:
@@ -151,8 +152,8 @@
{
// Load the class from the requesting bundle.
Class requestClass =
- ((BundleImpl) requester).getInfo().getCurrentModule().getClassLoader()
- .loadClass(className);
+ ((BundleImpl) requester).getInfo().getCurrentModule().getContentLoader()
+ .getClass(className);
// Get the service registration and ask it to check
// if the service object is assignable to the requesting
// bundle's class.
@@ -168,7 +169,7 @@
// same source module.
else
{
- allow = providerWire.m_module.equals(requesterWire.m_module);
+ allow = providerWire.getExportingModule().equals(requesterWire.getExportingModule());
}
return allow;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
index 5f52889..f8a15a0 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
@@ -174,7 +174,7 @@
catch (Exception ex)
{
m_registry.getLogger().log(
- LogWrapper.LOG_ERROR, "ServiceRegistrationImpl: Error getting service.", ex);
+ Logger.LOG_ERROR, "ServiceRegistrationImpl: Error getting service.", ex);
return null;
}
}
@@ -205,7 +205,7 @@
catch (Exception ex)
{
m_registry.getLogger().log(
- LogWrapper.LOG_ERROR, "ServiceRegistrationImpl: Error ungetting service.", ex);
+ Logger.LOG_ERROR, "ServiceRegistrationImpl: Error ungetting service.", ex);
}
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
index ccf3d40..f65e9be 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -23,7 +23,7 @@
public class ServiceRegistry
{
- private LogWrapper m_logger = null;
+ private Logger m_logger = null;
private long m_currentServiceId = 1L;
// Maps bundle to an array of service registrations.
private Map m_serviceRegsMap = new HashMap();
@@ -32,7 +32,7 @@
private ServiceListener m_serviceListener = null;
- public ServiceRegistry(LogWrapper logger)
+ public ServiceRegistry(Logger logger)
{
m_logger = logger;
}
@@ -337,7 +337,7 @@
fireServiceChanged(new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()));
}
- public LogWrapper getLogger()
+ public Logger getLogger()
{
return m_logger;
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundle.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundle.java
index 8718142..b089de8 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundle.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundle.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,19 +24,16 @@
import org.apache.felix.framework.searchpolicy.*;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.StringMap;
-import org.apache.felix.moduleloader.LibrarySource;
-import org.apache.felix.moduleloader.ResourceSource;
+import org.apache.felix.moduleloader.IContentLoader;
import org.osgi.framework.*;
-
class SystemBundle extends BundleImpl
{
private List m_activatorList = null;
private BundleActivator m_activator = null;
private Thread m_shutdownThread = null;
- private Object[][] m_attributes = null;
- private ResourceSource[] m_resSources = null;
- private LibrarySource[] m_libSources = null;
+ private R4Export[] m_exports = null;
+ private IContentLoader m_contentLoader = null;
protected SystemBundle(Felix felix, BundleInfo info, List activatorList)
throws BundleException
@@ -74,62 +71,59 @@
}
catch (Exception ex)
{
+ classPathPkgs = new R4Package[0];
getFelix().getLogger().log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Error parsing system bundle export statement.", ex);
}
// Now, create the list of standard framework exports for
// the system bundle.
- R4Package[] exports = new R4Package[classPathPkgs.length + 4];
+ m_exports = new R4Export[classPathPkgs.length + 4];
- exports[0] = new R4Package(
+ m_exports[0] = new R4Export(
"org.osgi.framework",
new R4Directive[0],
new R4Attribute[] { new R4Attribute("version", "1.3.0", false) });
- exports[1] = new R4Package(
+ m_exports[1] = new R4Export(
"org.osgi.service.packageadmin",
new R4Directive[0],
new R4Attribute[] { new R4Attribute("version", "1.2.0", false) });
- exports[2] = new R4Package(
+ m_exports[2] = new R4Export(
"org.osgi.service.startlevel",
new R4Directive[0],
new R4Attribute[] { new R4Attribute("version", "1.0.0", false) });
- exports[3] = new R4Package(
+ m_exports[3] = new R4Export(
"org.osgi.service.url",
new R4Directive[0],
new R4Attribute[] { new R4Attribute("version", "1.0.0", false) });
// Copy the class path exported packages.
- System.arraycopy(classPathPkgs, 0, exports, 4, classPathPkgs.length);
+ for (int i = 0; i < classPathPkgs.length; i++)
+ {
+ m_exports[i + 4] = new R4Export(classPathPkgs[i]);
+ }
- m_attributes = new Object[][] {
- new Object[] { R4SearchPolicy.EXPORTS_ATTR, exports },
- new Object[] { R4SearchPolicy.IMPORTS_ATTR, new R4Package[0] }
- };
-
- m_resSources = new ResourceSource[0];
-
- m_libSources = null;
+ m_contentLoader = new SystemBundleContentLoader(getFelix().getLogger());
String exportString = "";
- for (int i = 0; i < exports.length; i++)
+ for (int i = 0; i < m_exports.length; i++)
{
exportString = exportString +
- exports[i].getId()
+ m_exports[i].getName()
+ "; specification-version=\""
- + exports[i].getVersionLow().toString() + "\"";
+ + m_exports[i].getVersion().toString() + "\"";
- if (i < (exports.length - 1))
+ if (i < (m_exports.length - 1))
{
exportString = exportString + ", ";
exportString = exportString +
- exports[i].getId()
+ m_exports[i].getName()
+ "; specification-version=\""
- + exports[i].getVersionLow().toString() + "\", ";
+ + m_exports[i].getVersion().toString() + "\", ";
}
}
@@ -143,19 +137,14 @@
((SystemBundleArchive) getInfo().getArchive()).setManifestHeader(map);
}
- public Object[][] getAttributes()
+ public R4Export[] getExports()
{
- return m_attributes;
+ return m_exports;
}
- public ResourceSource[] getResourceSources()
+ public IContentLoader getContentLoader()
{
- return m_resSources;
- }
-
- public LibrarySource[] getLibrarySources()
- {
- return m_libSources;
+ return m_contentLoader;
}
public synchronized void start() throws BundleException
@@ -173,7 +162,6 @@
getInfo().setContext(new BundleContextImpl(getFelix(), this));
getActivator().start(getInfo().getContext());
} catch (Throwable throwable) {
-throwable.printStackTrace();
throw new BundleException(
"Unable to start system bundle.", throwable);
}
@@ -205,7 +193,7 @@
catch (Exception ex)
{
getFelix().getLogger().log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"SystemBundle: Error while shutting down.", ex);
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java
index 8e70fd3..0547655 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
import org.apache.felix.framework.cache.BundleArchive;
import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.moduleloader.IContent;
+import org.apache.felix.moduleloader.IContentLoader;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
@@ -67,7 +69,7 @@
return null;
}
- public BundleActivator getActivator(ClassLoader loader)
+ public BundleActivator getActivator(IContentLoader contentLoader)
throws Exception
{
return null;
@@ -95,7 +97,13 @@
m_headerMap = headerMap;
}
- public String[] getClassPath(int revision)
+ public IContent getContent(int revision)
+ throws Exception
+ {
+ return null;
+ }
+
+ public IContent[] getContentPath(int revision)
throws Exception
{
return null;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java
new file mode 100644
index 0000000..aa20c2f
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.felix.moduleloader.*;
+
+public class SystemBundleContentLoader implements IContentLoader
+{
+ private Logger m_logger = null;
+ private ISearchPolicy m_searchPolicy = null;
+ private IURLPolicy m_urlPolicy = null;
+
+ public SystemBundleContentLoader(Logger logger)
+ {
+ m_logger = logger;
+ }
+
+ public void open()
+ {
+ // Nothing needed here.
+ }
+
+ public void close()
+ {
+ // Nothing needed here.
+ }
+
+ public IContent getContent()
+ {
+ return null;
+ }
+
+ public ISearchPolicy getSearchPolicy()
+ {
+ return m_searchPolicy;
+ }
+
+ public void setSearchPolicy(ISearchPolicy searchPolicy)
+ {
+ m_searchPolicy = searchPolicy;
+ }
+
+ public IURLPolicy getURLPolicy()
+ {
+ return m_urlPolicy;
+ }
+
+ public void setURLPolicy(IURLPolicy urlPolicy)
+ {
+ m_urlPolicy = urlPolicy;
+ }
+
+ public Class getClass(String name)
+ {
+ try
+ {
+ return getClass().getClassLoader().loadClass(name);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ m_logger.log(
+ Logger.LOG_WARNING,
+ ex.getMessage(),
+ ex);
+ }
+ return null;
+ }
+
+ public URL getResource(String name)
+ {
+ return getClass().getClassLoader().getResource(name);
+ }
+
+ public InputStream getResourceAsStream(String name) throws IOException
+ {
+ return getClass().getClassLoader().getResourceAsStream(name);
+ }
+
+ public String findLibrary(String name)
+ {
+ // No native libs associated with the system bundle.
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlers.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlers.java
index e7536ee..4fcb8e0 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlers.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlers.java
@@ -19,8 +19,8 @@
import java.net.*;
import java.util.*;
+import org.apache.felix.framework.searchpolicy.ContentClassLoader;
import org.apache.felix.framework.util.*;
-import org.apache.felix.moduleloader.ModuleClassLoader;
import org.osgi.framework.BundleContext;
/**
@@ -345,7 +345,7 @@
Class targetClass = null;
for (int i = 0; i < stack.length; i++)
{
- if (stack[i].getClassLoader() instanceof ModuleClassLoader)
+ if (stack[i].getClassLoader() instanceof ContentClassLoader)
{
targetClass = stack[i];
break;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
index 551373e..9c5b05e 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@
import java.net.URLConnection;
import java.security.Permission;
+import org.apache.felix.framework.util.Util;
+
class URLHandlersBundleURLConnection extends URLConnection
{
private Felix m_framework;
@@ -54,8 +56,18 @@
throw new IOException("Unable to find framework instance from context.");
}
- m_is = m_framework.getBundleResourceInputStream(url);
- m_contentLength = m_is.available();
+ // The URL is constructed like this:
+ // bundle://<module-id>/<resource-path>
+ // Where <module-id> = <bundle-id>.<revision>
+ long bundleId = Util.getBundleIdFromModuleId(url.getHost());
+ BundleImpl bundle = (BundleImpl) m_framework.getBundle(bundleId);
+ if (bundle == null)
+ {
+ throw new IOException("Unable to find bundle.");
+ }
+ int revision = Util.getModuleRevisionFromModuleId(url.getHost());
+ m_is = bundle.getInfo().getModules()[revision].getContentLoader().getResourceAsStream(url.getPath());
+ m_contentLength = (m_is == null) ? 0 : m_is.available();
m_contentTime = 0L;
m_contentType = URLConnection.guessContentTypeFromName(url.getFile());
connected = true;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index 85dc382..b0f6aec 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
import java.io.File;
import java.util.Map;
+import org.apache.felix.moduleloader.IContent;
+import org.apache.felix.moduleloader.IContentLoader;
import org.osgi.framework.BundleActivator;
/**
@@ -117,7 +119,7 @@
* this archive.
* @throws java.lang.Exception if any error occurs.
**/
- public BundleActivator getActivator(ClassLoader loader)
+ public BundleActivator getActivator(IContentLoader contentLoader)
throws Exception;
/**
@@ -162,19 +164,27 @@
/**
* <p>
- * Returns an array of <tt>String</tt>s that represent the class path of
- * the specified revision of the bundle associated with this archive.
- * Currently, these values are restricted to absolute paths in the file
- * system, but this may be lifted in the future (perhaps they should be
- * <tt>ResourceSource</tt>s from the Module Loader.
+ * Returns a content object that is associated with the specified bundle
+ * revision's JAR file.
* </p>
* @param revision the specified revision.
- * @return a <tt>String</tt> array of the absolute path names that
- * comprise the class path of the specified revision of the
- * bundle associated with this archive.
+ * @return A content object for the specified bundle revision's JAR file.
* @throws java.lang.Exception if any error occurs.
**/
- public String[] getClassPath(int revision)
+ public IContent getContent(int revision)
+ throws Exception;
+
+ /**
+ * <p>
+ * Returns an array of content objects that are associated with the
+ * specified bundle revision's class path.
+ * </p>
+ * @param revision the specified revision.
+ * @return An array of content objects for the specified bundle revision's
+ * class path.
+ * @throws java.lang.Exception if any error occurs.
+ **/
+ public IContent[] getContentPath(int revision)
throws Exception;
/**
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
index 33b4a35..a1ddc76 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
@@ -18,7 +18,7 @@
import java.io.InputStream;
-import org.apache.felix.framework.LogWrapper;
+import org.apache.felix.framework.Logger;
import org.apache.felix.framework.util.PropertyResolver;
/**
@@ -58,7 +58,7 @@
* @param logger the logger to use for reporting errors.
* @throws Exception if any error occurs.
**/
- public void initialize(PropertyResolver cfg, LogWrapper logger)
+ public void initialize(PropertyResolver cfg, Logger logger)
throws Exception;
/**
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java
index d449099..101f067 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,10 @@
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
-import org.apache.felix.framework.LogWrapper;
+import org.apache.felix.framework.Logger;
import org.apache.felix.framework.util.*;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.moduleloader.*;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
@@ -53,7 +55,7 @@
private static final transient String INSTALLED_STATE = "installed";
private static final transient String UNINSTALLED_STATE = "uninstalled";
- private LogWrapper m_logger = null;
+ private Logger m_logger = null;
private long m_id = -1;
private File m_dir = null;
private String m_location = null;
@@ -64,7 +66,8 @@
private long m_refreshCount = -1;
private int m_revisionCount = -1;
- public DefaultBundleArchive(LogWrapper logger, File dir, long id, String location, InputStream is)
+ public DefaultBundleArchive(
+ Logger logger, File dir, long id, String location, InputStream is)
throws Exception
{
this(logger, dir, id);
@@ -80,14 +83,14 @@
if (!deleteDirectoryTree(dir))
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to delete the archive directory: " + id);
}
throw ex;
}
}
- public DefaultBundleArchive(LogWrapper logger, File dir, long id)
+ public DefaultBundleArchive(Logger logger, File dir, long id)
{
m_logger = logger;
m_dir = dir;
@@ -133,7 +136,7 @@
if (!m_dir.mkdir())
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Unable to create archive directory.");
throw new IOException("Unable to create archive directory.");
}
@@ -152,7 +155,7 @@
if (!revisionDir.mkdir())
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Unable to create revision directory.");
throw new IOException("Unable to create revision directory.");
}
@@ -354,7 +357,7 @@
catch (IOException ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Unable to record state: " + ex);
throw ex;
}
@@ -463,7 +466,7 @@
catch (IOException ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Unable to record start leel: " + ex);
throw ex;
}
@@ -521,7 +524,7 @@
}
}
- public BundleActivator getActivator(ClassLoader loader)
+ public BundleActivator getActivator(IContentLoader contentLoader)
throws Exception
{
if (System.getSecurityManager() != null)
@@ -530,7 +533,7 @@
{
return (BundleActivator) AccessController.doPrivileged(
new PrivilegedAction(
- PrivilegedAction.GET_ACTIVATOR_ACTION, this, loader));
+ PrivilegedAction.GET_ACTIVATOR_ACTION, this, contentLoader));
}
catch (PrivilegedActionException ex)
{
@@ -539,11 +542,11 @@
}
else
{
- return getActivatorUnchecked(loader);
+ return getActivatorUnchecked(contentLoader);
}
}
- private BundleActivator getActivatorUnchecked(ClassLoader loader)
+ private BundleActivator getActivatorUnchecked(IContentLoader contentLoader)
throws Exception
{
// Get bundle activator file.
@@ -559,14 +562,14 @@
try
{
is = new FileInputStream(activatorFile);
- ois = new ObjectInputStreamX(is, loader);
+ ois = new ObjectInputStreamX(is, contentLoader);
Object o = ois.readObject();
return (BundleActivator) o;
}
catch (Exception ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Trying to deserialize - " + ex);
}
finally
@@ -623,7 +626,7 @@
catch (IOException ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Unable to serialize activator - " + ex);
throw ex;
}
@@ -741,16 +744,28 @@
return new JarFile(bundleJar);
}
- public String[] getClassPath(int revision)
+ private IContent getContentUnchecked(int revision)
throws Exception
{
+ // Get the revision directory.
+ File revisionDir = new File(
+ m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
+ // Return a content object for the bundle itself.
+ return new JarContent(new File(revisionDir, BUNDLE_JAR_FILE));
+ }
+
+ public IContent getContent(int revision)
+ throws Exception
+ {
+ IContent content = null;
+
if (System.getSecurityManager() != null)
{
try
{
- return (String []) AccessController.doPrivileged(
+ content = (IContent) AccessController.doPrivileged(
new PrivilegedAction(
- PrivilegedAction.GET_CLASS_PATH_ACTION, this, revision));
+ PrivilegedAction.GET_CONTENT_ACTION, this, revision));
}
catch (PrivilegedActionException ex)
{
@@ -759,16 +774,24 @@
}
else
{
- return getClassPathUnchecked(revision);
+ content = getContentUnchecked(revision);
}
+
+ return content;
}
- private String[] getClassPathUnchecked(int revision)
+ private IContent[] getContentPathUnchecked(int revision)
throws Exception
{
+ // Creating the content path entails examining the bundle's
+ // class path to determine whether the bundle JAR file itself
+ // is on the bundle's class path and then creating content
+ // objects for everything on the class path.
+
// Get the revision directory.
File revisionDir = new File(
m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
+ File embedDir = new File(revisionDir, EMBEDDED_DIRECTORY);
// Get the bundle's manifest header.
Map map = getManifestHeader(revision);
@@ -778,75 +801,79 @@
}
// Find class path meta-data.
- String classPath = null;
+ String classPathString = null;
Iterator iter = map.entrySet().iterator();
- while ((classPath == null) && iter.hasNext())
+ while ((classPathString == null) && iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
if (entry.getKey().toString().toLowerCase().equals(
FelixConstants.BUNDLE_CLASSPATH.toLowerCase()))
{
- classPath = entry.getValue().toString();
+ classPathString = entry.getValue().toString();
}
}
// Parse the class path into strings.
String[] classPathStrings = Util.parseDelimitedString(
- classPath, FelixConstants.CLASS_PATH_SEPARATOR);
+ classPathString, FelixConstants.CLASS_PATH_SEPARATOR);
if (classPathStrings == null)
{
classPathStrings = new String[0];
}
- // Now, check for "." in the class path.
- boolean includeDot = false;
- for (int i = 0; !includeDot && (i < classPathStrings.length); i++)
+ // Create the bundles class path.
+ IContent self = new JarContent(new File(revisionDir, BUNDLE_JAR_FILE));
+ IContent[] classPath = new IContent[classPathStrings.length];
+ for (int i = 0; i < classPathStrings.length; i++)
{
if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
{
- includeDot = true;
+ classPath[i] = self;
}
- }
-
- // Include all JARs in the embedded jar directory, since they
- // were extracted when the bundle was initially saved.
- File embedDir = new File(revisionDir, EMBEDDED_DIRECTORY);
- String[] paths = null;
- if (embedDir.exists())
- {
- // The size of the paths array is the number of
- // embedded JAR files plus one, if we need to include
- // ".", otherwise it is just the number of JAR files.
- // If "." is included, then it will be added to the
- // first place in the path array below.
- File[] children = embedDir.listFiles();
- int size = (children == null) ? 0 : children.length;
- size = (includeDot) ? size + 1 : size;
- paths = new String[size];
- for (int i = 0; i < children.length; i++)
+ else
{
- // If we are including "." then skip the first slot,
- // because this is where we will put the bundle JAR file.
- paths[(includeDot) ? i + 1 : i] = children[i].getPath();
+ String jarName = (classPathStrings[i].lastIndexOf('/') >= 0)
+ ? classPathStrings[i].substring(classPathStrings[i].lastIndexOf('/') + 1)
+ : classPathStrings[i];
+ classPath[i] = new JarContent(new File(embedDir, jarName));
}
}
// If there is nothing on the class path, then include
// "." by default, as per the spec.
- if ((paths == null) || (paths.length == 0))
+ if (classPath.length == 0)
{
- includeDot = true;
- paths = new String[1];
+ classPath = new IContent[] { self };
}
- // Put the bundle jar file first, if included.
- if (includeDot)
+ return classPath;
+ }
+
+ public IContent[] getContentPath(int revision)
+ throws Exception
+ {
+ IContent[] contents = null;
+
+ if (System.getSecurityManager() != null)
{
- paths[0] = revisionDir + File.separator + BUNDLE_JAR_FILE;
+ try
+ {
+ contents = (IContent[]) AccessController.doPrivileged(
+ new PrivilegedAction(
+ PrivilegedAction.GET_CONTENT_PATH_ACTION, this, revision));
+ }
+ catch (PrivilegedActionException ex)
+ {
+ throw ((PrivilegedActionException) ex).getException();
+ }
+ }
+ else
+ {
+ contents = getContentPathUnchecked(revision);
}
- return paths;
+ return contents;
}
// TODO: This will need to consider security.
@@ -999,7 +1026,7 @@
catch (IOException ex)
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"DefaultBundleArchive: Unable to write counter: " + ex);
throw ex;
}
@@ -1159,6 +1186,8 @@
// Remove leading slash if present.
jarPath = (jarPath.charAt(0) == '/') ? jarPath.substring(1) : jarPath;
// Get only the JAR file name.
+// TODO: FIX THIS SO THAT IT CREATES DIRECTORIES TO AVOID NAME CLASHES,
+// DOING SO WILL IMPACT getContentLoaderUnchecked() METHOD ABOVE.
String jarName = (jarPath.lastIndexOf('/') >= 0)
? jarPath.substring(jarPath.lastIndexOf('/') + 1) : jarPath;
@@ -1254,7 +1283,7 @@
{
// There is very little we can do here.
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to remove partial revision directory.", ex2);
}
}
@@ -1368,16 +1397,17 @@
private static final int SET_START_LEVEL_ACTION = 9;
private static final int OPEN_BUNDLE_JAR_ACTION = 10;
private static final int CREATE_DATA_DIR_ACTION = 11;
- private static final int GET_CLASS_PATH_ACTION = 12;
- private static final int GET_ACTIVATOR_ACTION = 13;
- private static final int SET_ACTIVATOR_ACTION = 14;
+ private static final int GET_CONTENT_ACTION = 12;
+ private static final int GET_CONTENT_PATH_ACTION = 13;
+ private static final int GET_ACTIVATOR_ACTION = 14;
+ private static final int SET_ACTIVATOR_ACTION = 15;
private int m_action = 0;
private DefaultBundleArchive m_archive = null;
private InputStream m_isArg = null;
private int m_intArg = 0;
private File m_fileArg = null;
- private ClassLoader m_loaderArg = null;
+ private IContentLoader m_contentLoaderArg = null;
private Object m_objArg = null;
public PrivilegedAction(int action, DefaultBundleArchive archive)
@@ -1407,11 +1437,11 @@
m_fileArg = fileArg;
}
- public PrivilegedAction(int action, DefaultBundleArchive archive, ClassLoader loaderArg)
+ public PrivilegedAction(int action, DefaultBundleArchive archive, IContentLoader contentLoaderArg)
{
m_action = action;
m_archive = archive;
- m_loaderArg = loaderArg;
+ m_contentLoaderArg = contentLoaderArg;
}
public PrivilegedAction(int action, DefaultBundleArchive archive, Object objArg)
@@ -1456,10 +1486,12 @@
case CREATE_DATA_DIR_ACTION:
m_archive.createDataDirectoryUnchecked(m_fileArg);
return null;
- case GET_CLASS_PATH_ACTION:
- return m_archive.getClassPathUnchecked(m_intArg);
+ case GET_CONTENT_ACTION:
+ return m_archive.getContentUnchecked(m_intArg);
+ case GET_CONTENT_PATH_ACTION:
+ return m_archive.getContentPathUnchecked(m_intArg);
case GET_ACTIVATOR_ACTION:
- return m_archive.getActivatorUnchecked(m_loaderArg);
+ return m_archive.getActivatorUnchecked(m_contentLoaderArg);
case SET_ACTIVATOR_ACTION:
m_archive.setActivatorUnchecked(m_objArg);
return null;
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleCache.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleCache.java
index c1568a6..eb0499d 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleCache.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleCache.java
@@ -18,7 +18,7 @@
import java.io.*;
-import org.apache.felix.framework.LogWrapper;
+import org.apache.felix.framework.Logger;
import org.apache.felix.framework.util.PropertyResolver;
/**
@@ -77,7 +77,7 @@
protected static transient final String BUNDLE_DIR_PREFIX = "bundle";
private PropertyResolver m_cfg = null;
- private LogWrapper m_logger = null;
+ private Logger m_logger = null;
private File m_profileDir = null;
private BundleArchive[] m_archives = null;
@@ -85,7 +85,7 @@
{
}
- public void initialize(PropertyResolver cfg, LogWrapper logger) throws Exception
+ public void initialize(PropertyResolver cfg, Logger logger) throws Exception
{
// Save Properties reference.
m_cfg = cfg;
@@ -154,7 +154,7 @@
if (!m_profileDir.mkdirs())
{
m_logger.log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"Unable to create directory: " + m_profileDir);
throw new RuntimeException("Unable to create profile directory.");
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java
new file mode 100644
index 0000000..8c73300
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.SecureClassLoader;
+import java.security.cert.Certificate;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.moduleloader.IContentLoader;
+import org.apache.felix.moduleloader.ResourceNotFoundException;
+
+public class ContentClassLoader extends SecureClassLoader
+{
+ private ContentLoaderImpl m_contentLoader = null;
+
+ ContentClassLoader(ContentLoaderImpl contentLoader)
+ {
+ m_contentLoader = contentLoader;
+ }
+
+ public IContentLoader getContentLoader()
+ {
+ return m_contentLoader;
+ }
+
+ public Class loadClassFromModule(String name)
+ throws ClassNotFoundException
+ {
+ // Ask the search policy for the clas before consulting the module.
+ Class clazz = findClass(name);
+
+ // If not found, then throw an exception.
+ if (clazz == null)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ resolveClass(clazz);
+ return clazz;
+ }
+
+ protected Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ // Make sure the class was not already loaded.
+ Class clazz = findLoadedClass(name);
+ if (clazz == null)
+ {
+ // Ask the search policy for the class.
+ clazz = m_contentLoader.getSearchPolicy().findClass(name);
+ }
+
+ // If still not found, then throw an exception.
+ if (clazz == null)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ // Otherwise resolve the class.
+ if (resolve)
+ {
+ resolveClass(clazz);
+ }
+ return clazz;
+ }
+
+ protected Class findClass(String name) throws ClassNotFoundException
+ {
+ Class clazz = findLoadedClass(name);
+
+ // Search for class in module.
+ if (clazz == null)
+ {
+ String actual = name.replace('.', '/') + ".class";
+ byte[] bytes = null;
+
+ // Check the module class path.
+ for (int i = 0;
+ (bytes == null) &&
+ (i < m_contentLoader.getClassPath().length); i++)
+ {
+ bytes = m_contentLoader.getClassPath()[i].getEntry(actual);
+ }
+
+ if (bytes != null)
+ {
+ // We need to try to define a Package object for the class
+ // before we call defineClass(). Get the package name and
+ // see if we have already created the package.
+ String pkgName = Util.getClassPackage(name);
+ if (pkgName.length() > 0)
+ {
+ if (getPackage(pkgName) == null)
+ {
+ Object[] params =
+ m_contentLoader.getSearchPolicy()
+ .definePackage(pkgName);
+ if (params != null)
+ {
+ definePackage(
+ pkgName,
+ (String) params[0],
+ (String) params[1],
+ (String) params[2],
+ (String) params[3],
+ (String) params[4],
+ (String) params[5],
+ null);
+ }
+ else
+ {
+ definePackage(pkgName, null, null,
+ null, null, null, null, null);
+ }
+ }
+ }
+
+ // Get the code source URL for this class. For concurrency
+ // purposes, we are performing this call outside of the
+ // synchronized block below since we call out to application
+ // code, which might in turn need to call back into the
+ // module loader code. Because of this, it is better to
+ // not be holding any locks before making the call.
+ URL url = null;
+// TODO: FIX CODE SOURCE URL
+// URL url = m_mgr.getURLPolicy().createCodeSourceURL(
+// m_mgr, m_module);
+
+ // If we have a valid code source URL, then use it to
+ // define the class for security purposes, otherwise
+ // define the class without a code source.
+ if (url != null)
+ {
+ CodeSource cs = new CodeSource(url, (Certificate[]) null);
+ clazz = defineClass(name, bytes, 0, bytes.length, cs);
+ }
+ else
+ {
+ clazz = defineClass(name, bytes, 0, bytes.length);
+ }
+ }
+ }
+
+ if (clazz != null)
+ {
+ return clazz;
+ }
+
+ return null;
+ }
+
+ public URL getResourceFromModule(String name)
+ {
+ try
+ {
+ return findResource(name);
+ }
+ catch (Throwable th)
+ {
+ // Ignore and just return null.
+ }
+ return null;
+ }
+
+ public URL getResource(String name)
+ {
+ // Ask the search policy for the class before consulting the module.
+ try
+ {
+ return m_contentLoader.getSearchPolicy().findResource(name);
+ }
+ catch (ResourceNotFoundException ex)
+ {
+ m_contentLoader.getLogger().log(
+ Logger.LOG_WARNING,
+ ex.getMessage(),
+ ex);
+ }
+ return null;
+ }
+
+ protected URL findResource(String name)
+ {
+ URL url = null;
+
+ // Remove leading slash, if present.
+ if (name.startsWith("/"))
+ {
+ name = name.substring(1);
+ }
+
+ // Check the module class path.
+ for (int i = 0;
+ (url == null) &&
+ (i < m_contentLoader.getClassPath().length); i++)
+ {
+ if (m_contentLoader.getClassPath()[i].hasEntry(name))
+ {
+ url = m_contentLoader.getURLPolicy().createURL(i + "/" + name);
+ }
+ }
+
+ return url;
+ }
+
+ protected Enumeration findResources(String name)
+ {
+ Vector v = new Vector();
+
+ // Remove leading slash, if present.
+ if (name.startsWith("/"))
+ {
+ name = name.substring(1);
+ }
+
+ // Check the module class path.
+ for (int i = 0; i < m_contentLoader.getClassPath().length; i++)
+ {
+ if (m_contentLoader.getClassPath()[i].hasEntry(name))
+ {
+ v.addElement(m_contentLoader.getURLPolicy().createURL(i + "/" + name));
+ }
+ }
+
+ return v.elements();
+ }
+
+ protected String findLibrary(String name)
+ {
+ return m_contentLoader.getSearchPolicy().findLibrary(name);
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java
new file mode 100644
index 0000000..2abd263
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.moduleloader.*;
+
+public class ContentLoaderImpl implements IContentLoader
+{
+ private Logger m_logger = null;
+ private IContent m_content = null;
+ private IContent[] m_contentPath = null;
+ private ISearchPolicy m_searchPolicy = null;
+ private IURLPolicy m_urlPolicy = null;
+ private ContentClassLoader m_classLoader = null;
+
+ public ContentLoaderImpl(Logger logger, IContent content, IContent[] contentPath)
+ {
+ m_logger = logger;
+ m_content = content;
+ m_contentPath = contentPath;
+ }
+
+ public Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ public void open()
+ {
+ m_content.open();
+ for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++)
+ {
+ m_contentPath[i].open();
+ }
+ }
+
+ public void close()
+ {
+ m_content.close();
+ for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++)
+ {
+ m_contentPath[i].close();
+ }
+ }
+
+ public IContent getContent()
+ {
+ return m_content;
+ }
+
+ public IContent[] getClassPath()
+ {
+ return m_contentPath;
+ }
+
+ public void setSearchPolicy(ISearchPolicy searchPolicy)
+ {
+ m_searchPolicy = searchPolicy;
+ }
+
+ public ISearchPolicy getSearchPolicy()
+ {
+ return m_searchPolicy;
+ }
+
+ public void setURLPolicy(IURLPolicy urlPolicy)
+ {
+ m_urlPolicy = urlPolicy;
+ }
+
+ public IURLPolicy getURLPolicy()
+ {
+ return m_urlPolicy;
+ }
+
+ public Class getClass(String name)
+ {
+ if (m_classLoader == null)
+ {
+ m_classLoader = new ContentClassLoader(this);
+ }
+
+ try
+ {
+ return m_classLoader.loadClassFromModule(name);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ return null;
+ }
+ }
+
+ public URL getResource(String name)
+ {
+ if (m_classLoader == null)
+ {
+ m_classLoader = new ContentClassLoader(this);
+ }
+
+ return m_classLoader.getResourceFromModule(name);
+ }
+
+ public InputStream getResourceAsStream(String name)
+ throws IOException
+ {
+ if (name.startsWith("/"))
+ {
+ name = name.substring(1);
+ }
+ // The name is the path contructed like this:
+ // <class-path-index> / <relative-resource-path>
+ int idx = Integer.parseInt(name.substring(0, name.indexOf('/')));
+ name = name.substring(name.indexOf('/') + 1);
+ return m_contentPath[idx].getEntryAsStream(name);
+ }
+
+ public String toString()
+ {
+ return m_searchPolicy.toString();
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java
new file mode 100644
index 0000000..0a36b98
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/IR4SearchPolicy.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import org.apache.felix.moduleloader.ISearchPolicy;
+
+/**
+ * <p>
+ * This interface extends the search policy interface with specific
+ * methods related to implementing an R4 search policy. For the most
+ * part, this interface is really implementation specific and should
+ * not be used by any except the R4 search policy implementation or
+ * those that are very sure they know what they are doing. For example,
+ * just blindly calling the various setter methods will likely not
+ * provide the desired results.
+ * </p>
+**/
+public interface IR4SearchPolicy extends ISearchPolicy
+{
+ public R4Export[] getExports();
+ public void setExports(R4Export[] exports);
+
+ public R4Import[] getImports();
+ public void setImports(R4Import[] imports);
+
+ public R4Import[] getDynamicImports();
+ public void setDynamicImports(R4Import[] imports);
+
+ public R4Library[] getLibraries();
+ public void setLibraries(R4Library[] libraries);
+
+ public R4Wire[] getWires();
+ public void setWires(R4Wire[] wires);
+
+ public boolean isResolved();
+ public void setResolved(boolean resolved);
+ public void resolve() throws ResolveException;
+
+ public void addResolverListener(ResolveListener l);
+ public void removeResolverListener(ResolveListener l);
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
new file mode 100644
index 0000000..9378d9a
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import java.util.*;
+
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.Util;
+
+public class R4Export extends R4Package
+{
+ private String[] m_uses = null;
+ private String[][] m_includeFilter = null;
+ private String[][] m_excludeFilter = null;
+
+ public R4Export(R4Package pkg)
+ {
+ this(pkg.getName(), pkg.getDirectives(), pkg.getAttributes());
+ }
+
+ public R4Export(String name, R4Directive[] directives, R4Attribute[] attrs)
+ {
+ super(name, directives, attrs);
+
+ // Find all export directives: uses, mandatory, include, and exclude.
+ String mandatory = "", uses = "";
+ for (int i = 0; i < m_directives.length; i++)
+ {
+ if (m_directives[i].getName().equals(FelixConstants.USES_DIRECTIVE))
+ {
+ uses = m_directives[i].getValue();
+ }
+ else if (m_directives[i].getName().equals(FelixConstants.MANDATORY_DIRECTIVE))
+ {
+ mandatory = m_directives[i].getValue();
+ }
+ else if (m_directives[i].getName().equals(FelixConstants.INCLUDE_DIRECTIVE))
+ {
+ String[] ss = Util.parseDelimitedString(m_directives[i].getValue(), ",");
+ m_includeFilter = new String[ss.length][];
+ for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
+ {
+ m_includeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+ }
+ }
+ else if (m_directives[i].getName().equals(FelixConstants.EXCLUDE_DIRECTIVE))
+ {
+ String[] ss = Util.parseDelimitedString(m_directives[i].getValue(), ",");
+ m_excludeFilter = new String[ss.length][];
+ for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
+ {
+ m_excludeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+ }
+ }
+ }
+
+ // Parse these uses directive.
+ StringTokenizer tok = new StringTokenizer(uses, ",");
+ m_uses = new String[tok.countTokens()];
+ for (int i = 0; i < m_uses.length; i++)
+ {
+ m_uses[i] = tok.nextToken().trim();
+ }
+
+ // Parse mandatory directive and mark specified
+ // attributes as mandatory.
+ tok = new StringTokenizer(mandatory, ",");
+ while (tok.hasMoreTokens())
+ {
+ // Get attribute name.
+ String attrName = tok.nextToken().trim();
+ // Find attribute and mark it as mandatory.
+ boolean found = false;
+ for (int i = 0; (!found) && (i < m_attrs.length); i++)
+ {
+ if (m_attrs[i].getName().equals(attrName))
+ {
+ m_attrs[i] = new R4Attribute(
+ m_attrs[i].getName(),
+ m_attrs[i].getValue(), true);
+ found = true;
+ }
+ }
+ // If a specified mandatory attribute was not found,
+ // then error.
+ if (!found)
+ {
+ throw new IllegalArgumentException(
+ "Mandatory attribute '" + attrName + "' does not exist.");
+ }
+ }
+
+ // Find and parse version attribute, if present.
+ String rangeStr = "0.0.0";
+ for (int i = 0; i < m_attrs.length; i++)
+ {
+ if (m_attrs[i].getName().equals(FelixConstants.VERSION_ATTRIBUTE) ||
+ m_attrs[i].getName().equals(FelixConstants.PACKAGE_SPECIFICATION_VERSION))
+ {
+ // Normalize version attribute name.
+ m_attrs[i] = new R4Attribute(
+ FelixConstants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
+ m_attrs[i].isMandatory());
+ rangeStr = m_attrs[i].getValue();
+ break;
+ }
+ }
+
+ VersionRange range = VersionRange.parse(rangeStr);
+ // For now, ignore if we have a version range.
+ m_version = range.getLow();
+ }
+
+ public String[] getUses()
+ {
+ return m_uses;
+ }
+
+ public boolean isIncluded(String name)
+ {
+ if ((m_includeFilter == null) && (m_excludeFilter == null))
+ {
+ return true;
+ }
+
+ // Get the class name portion of the target class.
+ String className = Util.getClassName(name);
+
+ // If there are no include filters then all classes are included
+ // by default, otherwise try to find one match.
+ boolean included = (m_includeFilter == null);
+ for (int i = 0;
+ (!included) && (m_includeFilter != null) && (i < m_includeFilter.length);
+ i++)
+ {
+ included = checkSubstring(m_includeFilter[i], className);
+ }
+
+ // If there are no exclude filters then no classes are excluded
+ // by default, otherwise try to find one match.
+ boolean excluded = false;
+ for (int i = 0;
+ (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.length);
+ i++)
+ {
+ excluded = checkSubstring(m_excludeFilter[i], className);
+ }
+ return included && !excluded;
+ }
+
+ //
+ // The following substring-related code was lifted and modified
+ // from the LDAP parser code.
+ //
+
+ private static String[] parseSubstring(String target)
+ {
+ List pieces = new ArrayList();
+ StringBuffer ss = new StringBuffer();
+ // int kind = SIMPLE; // assume until proven otherwise
+ boolean wasStar = false; // indicates last piece was a star
+ boolean leftstar = false; // track if the initial piece is a star
+ boolean rightstar = false; // track if the final piece is a star
+
+ int idx = 0;
+
+ // We assume (sub)strings can contain leading and trailing blanks
+loop: for (;;)
+ {
+ if (idx >= target.length())
+ {
+ if (wasStar)
+ {
+ // insert last piece as "" to handle trailing star
+ rightstar = true;
+ }
+ else
+ {
+ pieces.add(ss.toString());
+ // accumulate the last piece
+ // note that in the case of
+ // (cn=); this might be
+ // the string "" (!=null)
+ }
+ ss.setLength(0);
+ break loop;
+ }
+
+ char c = target.charAt(idx++);
+ if (c == '*')
+ {
+ if (wasStar)
+ {
+ // encountered two successive stars;
+ // I assume this is illegal
+ throw new IllegalArgumentException("Invalid filter string: " + target);
+ }
+ if (ss.length() > 0)
+ {
+ pieces.add(ss.toString()); // accumulate the pieces
+ // between '*' occurrences
+ }
+ ss.setLength(0);
+ // if this is a leading star, then track it
+ if (pieces.size() == 0)
+ {
+ leftstar = true;
+ }
+ ss.setLength(0);
+ wasStar = true;
+ }
+ else
+ {
+ wasStar = false;
+ ss.append(c);
+ }
+ }
+ if (leftstar || rightstar || pieces.size() > 1)
+ {
+ // insert leading and/or trailing "" to anchor ends
+ if (rightstar)
+ {
+ pieces.add("");
+ }
+ if (leftstar)
+ {
+ pieces.add(0, "");
+ }
+ }
+ return (String[]) pieces.toArray(new String[pieces.size()]);
+ }
+
+ private static boolean checkSubstring(String[] pieces, String s)
+ {
+ // Walk the pieces to match the string
+ // There are implicit stars between each piece,
+ // and the first and last pieces might be "" to anchor the match.
+ // assert (pieces.length > 1)
+ // minimal case is <string>*<string>
+
+ boolean result = false;
+ int len = pieces.length;
+
+loop: for (int i = 0; i < len; i++)
+ {
+ String piece = (String) pieces[i];
+ int index = 0;
+ if (i == len - 1)
+ {
+ // this is the last piece
+ if (s.endsWith(piece))
+ {
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+ break loop;
+ }
+ // initial non-star; assert index == 0
+ else if (i == 0)
+ {
+ if (!s.startsWith(piece))
+ {
+ result = false;
+ break loop;
+ }
+ }
+ // assert i > 0 && i < len-1
+ else
+ {
+ // Sure wish stringbuffer supported e.g. indexOf
+ index = s.indexOf(piece, index);
+ if (index < 0)
+ {
+ result = false;
+ break loop;
+ }
+ }
+ // start beyond the matching piece
+ index += piece.length();
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
new file mode 100644
index 0000000..6b56936
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import org.apache.felix.framework.util.FelixConstants;
+import org.osgi.framework.Version;
+
+public class R4Import extends R4Package
+{
+ private VersionRange m_versionRange = null;
+ private boolean m_isOptional = false;
+
+ public R4Import(R4Package pkg)
+ {
+ this(pkg.getName(), pkg.getDirectives(), pkg.getAttributes());
+ }
+
+ public R4Import(String name, R4Directive[] directives, R4Attribute[] attrs)
+ {
+ super(name, directives, attrs);
+
+ // Find all import directives: resolution.
+ for (int i = 0; i < m_directives.length; i++)
+ {
+ if (m_directives[i].getName().equals(FelixConstants.RESOLUTION_DIRECTIVE))
+ {
+ m_isOptional = m_directives[i].getValue().equals(FelixConstants.RESOLUTION_OPTIONAL);
+ }
+ }
+
+ // Find and parse version attribute, if present.
+ String rangeStr = "0.0.0";
+ for (int i = 0; i < m_attrs.length; i++)
+ {
+ if (m_attrs[i].getName().equals(FelixConstants.VERSION_ATTRIBUTE) ||
+ m_attrs[i].getName().equals(FelixConstants.PACKAGE_SPECIFICATION_VERSION))
+ {
+ // Normalize version attribute name.
+ m_attrs[i] = new R4Attribute(
+ FelixConstants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
+ m_attrs[i].isMandatory());
+ rangeStr = m_attrs[i].getValue();
+ break;
+ }
+ }
+
+ m_versionRange = VersionRange.parse(rangeStr);
+ m_version = m_versionRange.getLow();
+ }
+
+ public Version getVersionHigh()
+ {
+ return m_versionRange.getHigh();
+ }
+
+ public boolean isLowInclusive()
+ {
+ return m_versionRange.isLowInclusive();
+ }
+
+ public boolean isHighInclusive()
+ {
+ return m_versionRange.isHighInclusive();
+ }
+
+ public boolean isOptional()
+ {
+ return m_isOptional;
+ }
+
+ public boolean isSatisfied(R4Export export)
+ {
+ // For packages to be compatible, they must have the
+ // same name.
+ if (!getName().equals(export.getName()))
+ {
+ return false;
+ }
+
+ return m_versionRange.isInRange(export.getVersion())
+ && doAttributesMatch(export);
+ }
+
+ private boolean doAttributesMatch(R4Export export)
+ {
+ // Cycle through all attributes of this import package
+ // and make sure its values match the attribute values
+ // of the specified export package.
+ for (int impAttrIdx = 0; impAttrIdx < getAttributes().length; impAttrIdx++)
+ {
+ // Get current attribute from this import package.
+ R4Attribute impAttr = getAttributes()[impAttrIdx];
+
+ // Ignore version attribute, since it is a special case that
+ // has already been compared using isVersionInRange() before
+ // the call to this method was made.
+ if (impAttr.getName().equals(FelixConstants.VERSION_ATTRIBUTE))
+ {
+ continue;
+ }
+
+ // Check if the export package has the same attribute.
+ boolean found = false;
+ for (int expAttrIdx = 0;
+ (!found) && (expAttrIdx < export.getAttributes().length);
+ expAttrIdx++)
+ {
+ // Get current attribute for the export package.
+ R4Attribute expAttr = export.getAttributes()[expAttrIdx];
+ // Check if the attribute names are equal.
+ if (impAttr.getName().equals(expAttr.getName()))
+ {
+ // If the values are not equal, then return false immediately.
+ // We should not compare version values here, since they are
+ // a special case and have already been compared by a call to
+ // isVersionInRange() before getting here; however, it is
+ // possible for version to be mandatory, so make sure it is
+ // present below.
+ if (!impAttr.getValue().equals(expAttr.getValue()))
+ {
+ return false;
+ }
+ found = true;
+ }
+ }
+ // If the attribute was not found, then return false.
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ // Now, cycle through all attributes of the export package and verify that
+ // all mandatory attributes are present in this import package.
+ for (int expAttrIdx = 0; expAttrIdx < export.getAttributes().length; expAttrIdx++)
+ {
+ // Get current attribute for this package.
+ R4Attribute expAttr = export.getAttributes()[expAttrIdx];
+
+ // If the export attribute is mandatory, then make sure
+ // this import package has the attribute.
+ if (expAttr.isMandatory())
+ {
+ boolean found = false;
+ for (int impAttrIdx = 0;
+ (!found) && (impAttrIdx < getAttributes().length);
+ impAttrIdx++)
+ {
+ // Get current attribute from specified package.
+ R4Attribute impAttr = getAttributes()[impAttrIdx];
+
+ // Check if the attribute names are equal
+ // and set found flag.
+ if (expAttr.getName().equals(impAttr.getName()))
+ {
+ found = true;
+ }
+ }
+ // If not found, then return false.
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/OSGiLibrarySource.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java
similarity index 67%
rename from org.apache.felix.framework/src/main/java/org/apache/felix/framework/OSGiLibrarySource.java
rename to org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java
index 4546d61..80bdada 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/OSGiLibrarySource.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,27 +14,25 @@
* limitations under the License.
*
*/
-package org.apache.felix.framework;
+package org.apache.felix.framework.searchpolicy;
+import org.apache.felix.framework.Logger;
import org.apache.felix.framework.cache.BundleCache;
-import org.apache.felix.framework.util.LibraryInfo;
-import org.apache.felix.moduleloader.LibrarySource;
import org.osgi.framework.Constants;
-public class OSGiLibrarySource implements LibrarySource
+public class R4Library
{
- private LogWrapper m_logger = null;
- private boolean m_opened = false;
+ private Logger m_logger = null;
private BundleCache m_cache = null;
private long m_bundleId = -1;
private int m_revision = -1;
private String m_os = null;
private String m_processor = null;
- private LibraryInfo[] m_libraries = null;
+ private R4LibraryHeader m_header = null;
- public OSGiLibrarySource(
- LogWrapper logger, BundleCache cache, long bundleId, int revision,
- String os, String processor, LibraryInfo[] libraries)
+ public R4Library(
+ Logger logger, BundleCache cache, long bundleId, int revision,
+ String os, String processor, R4LibraryHeader header)
{
m_logger = logger;
m_cache = cache;
@@ -42,51 +40,32 @@
m_revision = revision;
m_os = normalizePropertyValue(Constants.FRAMEWORK_OS_NAME, os);
m_processor = normalizePropertyValue(Constants.FRAMEWORK_PROCESSOR, processor);
- m_libraries = libraries;
+ m_header = header;
}
- public void open()
+ /**
+ * <p>
+ * Returns a file system path to the specified library.
+ * </p>
+ * @param name the name of the library that is being requested.
+ * @return a file system path to the specified library.
+ **/
+ public String getPath(String name)
{
- m_opened = true;
- }
-
- public void close()
- {
- m_opened = false;
- }
-
- public String getPath(String name) throws IllegalStateException
- {
- if (!m_opened)
- {
- throw new IllegalStateException("OSGiLibrarySource is not open");
- }
-
- if (m_libraries != null)
+ if (m_header != null)
{
String libname = System.mapLibraryName(name);
- // Check to see if we have a matching library.
- // TODO: This "matching" algorithm does not fully
- // match the spec and should be improved.
- LibraryInfo library = null;
- for (int i = 0; (library == null) && (i < m_libraries.length); i++)
- {
- boolean osOkay = checkOS(m_libraries[i].getOSNames());
- boolean procOkay = checkProcessor(m_libraries[i].getProcessors());
- if (m_libraries[i].getName().endsWith(libname) && osOkay && procOkay)
- {
- library = m_libraries[i];
- }
- }
-
- if (library != null)
+ // Check to see if the library matches.
+ boolean osOkay = checkOS(m_header.getOSNames());
+ boolean procOkay = checkProcessor(m_header.getProcessors());
+ if (m_header.getName().endsWith(libname) && osOkay && procOkay)
{
try {
return m_cache.getArchive(m_bundleId)
- .findLibrary(m_revision, library.getName());
+ .findLibrary(m_revision, m_header.getName());
} catch (Exception ex) {
- m_logger.log(LogWrapper.LOG_ERROR, "OSGiLibrarySource: Error finding library.", ex);
+ m_logger.log(Logger.LOG_ERROR, "R4Library: Error finding library.", ex);
}
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/LibraryInfo.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java
similarity index 89%
rename from org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/LibraryInfo.java
rename to org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java
index b6171e9..28fde9b 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/LibraryInfo.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,14 @@
* limitations under the License.
*
*/
-package org.apache.felix.framework.util;
+package org.apache.felix.framework.searchpolicy;
import java.util.*;
+import org.apache.felix.framework.Logger;
import org.osgi.framework.Constants;
-public class LibraryInfo
+public class R4LibraryHeader
{
private String m_name = null;
private String[] m_osnames = null;
@@ -28,7 +29,7 @@
private String[] m_processors = null;
private String[] m_languages = null;
- public LibraryInfo(String name, String[] osnames, String[] osversions,
+ public R4LibraryHeader(String name, String[] osnames, String[] osversions,
String[] processors, String[] languages)
{
m_name = name;
@@ -38,7 +39,7 @@
m_languages = languages;
}
- public LibraryInfo(LibraryInfo library)
+ public R4LibraryHeader(R4LibraryHeader library)
{
m_name = library.m_name;
m_osnames = library.m_osnames;
@@ -67,7 +68,7 @@
return m_processors;
}
- public static LibraryInfo[] parse(String s)
+ public static R4LibraryHeader[] parse(Logger logger, String s)
{
try
{
@@ -150,11 +151,11 @@
return null;
}
- LibraryInfo[] libraries = new LibraryInfo[libCount];
+ R4LibraryHeader[] libraries = new R4LibraryHeader[libCount];
for (int i = 0; i < libCount; i++)
{
libraries[i] =
- new LibraryInfo(
+ new R4LibraryHeader(
libs[i],
(String[]) osNameList.toArray(new String[0]),
(String[]) osVersionList.toArray(new String[0]),
@@ -167,7 +168,10 @@
}
catch (RuntimeException ex)
{
- ex.printStackTrace();
+ logger.log(
+ Logger.LOG_ERROR,
+ "Error parsing native library header.",
+ ex);
throw ex;
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
index a46e17f..b826760 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,140 +16,30 @@
*/
package org.apache.felix.framework.searchpolicy;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.Util;
+import org.osgi.framework.Version;
public class R4Package
{
- private String m_id = "";
- private R4Directive[] m_directives = null;
- private R4Attribute[] m_attrs = null;
- private R4Version m_versionLow = null;
- private R4Version m_versionHigh = null;
- private String[] m_uses = null;
- private boolean m_isOptional = false;
- private String[][] m_includeFilter = null;
- private String[][] m_excludeFilter = null;
+ private String m_name = "";
+ protected R4Directive[] m_directives = null;
+ protected R4Attribute[] m_attrs = null;
+ protected Version m_version = null;
- protected R4Package(R4Package pkg)
+ public R4Package(String name, R4Directive[] directives, R4Attribute[] attrs)
{
- m_id = pkg.m_id;
- m_directives = pkg.m_directives;
- m_attrs = pkg.m_attrs;
- m_versionLow = pkg.m_versionLow;
- m_versionHigh = pkg.m_versionHigh;
- m_uses = pkg.m_uses;
- m_isOptional = pkg.m_isOptional;
- m_includeFilter = pkg.m_includeFilter;
- m_excludeFilter = pkg.m_excludeFilter;
- }
-
- public R4Package(String id, R4Directive[] directives, R4Attribute[] attrs)
- {
- m_id = id;
+ m_name = name;
m_directives = (directives == null) ? new R4Directive[0] : directives;
m_attrs = (attrs == null) ? new R4Attribute[0] : attrs;
-
- // Find all directives: uses, mandatory, resolution, include, and exclude.
- String mandatory = "", uses = "";
- for (int i = 0; i < m_directives.length; i++)
- {
- if (m_directives[i].getName().equals(FelixConstants.USES_DIRECTIVE))
- {
- uses = m_directives[i].getValue();
- }
- else if (m_directives[i].getName().equals(FelixConstants.MANDATORY_DIRECTIVE))
- {
- mandatory = m_directives[i].getValue();
- }
- else if (m_directives[i].getName().equals(FelixConstants.RESOLUTION_DIRECTIVE))
- {
- m_isOptional = m_directives[i].getValue().equals(FelixConstants.RESOLUTION_OPTIONAL);
- }
- else if (m_directives[i].getName().equals(FelixConstants.INCLUDE_DIRECTIVE))
- {
- String[] ss = Util.parseDelimitedString(m_directives[i].getValue(), ",");
- m_includeFilter = new String[ss.length][];
- for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
- {
- m_includeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
- }
- }
- else if (m_directives[i].getName().equals(FelixConstants.EXCLUDE_DIRECTIVE))
- {
- String[] ss = Util.parseDelimitedString(m_directives[i].getValue(), ",");
- m_excludeFilter = new String[ss.length][];
- for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
- {
- m_excludeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
- }
- }
- }
-
- // Parse these uses directive.
- StringTokenizer tok = new StringTokenizer(uses, ",");
- m_uses = new String[tok.countTokens()];
- for (int i = 0; i < m_uses.length; i++)
- {
- m_uses[i] = tok.nextToken().trim();
- }
-
- // Parse mandatory directive and mark specified
- // attributes as mandatory.
- tok = new StringTokenizer(mandatory, ",");
- while (tok.hasMoreTokens())
- {
- // Get attribute name.
- String attrName = tok.nextToken().trim();
- // Find attribute and mark it as mandatory.
- boolean found = false;
- for (int i = 0; (!found) && (i < m_attrs.length); i++)
- {
- if (m_attrs[i].getName().equals(attrName))
- {
- m_attrs[i] = new R4Attribute(
- m_attrs[i].getName(), m_attrs[i].getValue(), true);
- found = true;
- }
- }
- // If a specified mandatory attribute was not found,
- // then error.
- if (!found)
- {
- throw new IllegalArgumentException(
- "Mandatory attribute '" + attrName + "' does not exist.");
- }
- }
-
- // Find and parse version attribute, if present.
- String versionInterval = "0.0.0";
- for (int i = 0; i < m_attrs.length; i++)
- {
- if (m_attrs[i].getName().equals(FelixConstants.VERSION_ATTRIBUTE) ||
- m_attrs[i].getName().equals(FelixConstants.PACKAGE_SPECIFICATION_VERSION))
- {
- // Normalize version attribute name.
- m_attrs[i] = new R4Attribute(
- FelixConstants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
- m_attrs[i].isMandatory());
- versionInterval = m_attrs[i].getValue();
- break;
- }
- }
-
- R4Version[] versions = parseVersionInterval(versionInterval);
- m_versionLow = versions[0];
- if (versions.length == 2)
- {
- m_versionHigh = versions[1];
- }
}
- public String getId()
+ public String getName()
{
- return m_id;
+ return m_name;
}
public R4Directive[] getDirectives()
@@ -162,185 +52,15 @@
return m_attrs;
}
- public R4Version getVersionLow()
+ public Version getVersion()
{
- return m_versionLow;
+ return m_version;
}
- public R4Version getVersionHigh()
- {
- return m_versionHigh;
- }
-
- public String[] getUses()
- {
- return m_uses;
- }
-
- public boolean isOptional()
- {
- return m_isOptional;
- }
-
- public boolean isIncluded(String name)
- {
- if ((m_includeFilter == null) && (m_excludeFilter == null))
- {
- return true;
- }
-
- // Get the class name portion of the target class.
- String className = org.apache.felix.moduleloader.Util.getClassName(name);
-
- // If there are no include filters then all classes are included
- // by default, otherwise try to find one match.
- boolean included = (m_includeFilter == null);
- for (int i = 0;
- (!included) && (m_includeFilter != null) && (i < m_includeFilter.length);
- i++)
- {
- included = checkSubstring(m_includeFilter[i], className);
- }
-
- // If there are no exclude filters then no classes are excluded
- // by default, otherwise try to find one match.
- boolean excluded = false;
- for (int i = 0;
- (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.length);
- i++)
- {
- excluded = checkSubstring(m_excludeFilter[i], className);
- }
- return included && !excluded;
- }
-
- // PREVIOUSLY PART OF COMPATIBILITY POLICY.
- public boolean doesSatisfy(R4Package pkg)
- {
- // For packages to be compatible, they must have the
- // same name.
- if (!m_id.equals(pkg.m_id))
- {
- return false;
- }
-
- return isVersionInRange(m_versionLow, pkg.m_versionLow, pkg.m_versionHigh)
- && doAttributesMatch(pkg);
- }
-
- // PREVIOUSLY PART OF COMPATIBILITY POLICY.
- public static boolean isVersionInRange(R4Version version, R4Version low, R4Version high)
- {
- // We might not have an upper end to the range.
- if (high == null)
- {
- return (version.compareTo(low) >= 0);
- }
- else if (low.isInclusive() && high.isInclusive())
- {
- return (version.compareTo(low) >= 0) && (version.compareTo(high) <= 0);
- }
- else if (high.isInclusive())
- {
- return (version.compareTo(low) > 0) && (version.compareTo(high) <= 0);
- }
- else if (low.isInclusive())
- {
- return (version.compareTo(low) >= 0) && (version.compareTo(high) < 0);
- }
-
- return (version.compareTo(low) > 0) && (version.compareTo(high) < 0);
- }
-
- private boolean doAttributesMatch(R4Package pkg)
- {
- // Cycle through all attributes of the specified package
- // and make sure their values match the attribute values
- // of this package.
- for (int attrIdx = 0; attrIdx < pkg.m_attrs.length; attrIdx++)
- {
- // Get current attribute from specified package.
- R4Attribute attr = pkg.m_attrs[attrIdx];
-
- // Ignore version attribute, since it is a special case that
- // has already been compared using isVersionInRange() before
- // the call to this method was made.
- if (attr.getName().equals(FelixConstants.VERSION_ATTRIBUTE))
- {
- continue;
- }
-
- // Check if this package has the same attribute.
- boolean found = false;
- for (int thisAttrIdx = 0;
- (!found) && (thisAttrIdx < m_attrs.length);
- thisAttrIdx++)
- {
- // Get current attribute for this package.
- R4Attribute thisAttr = m_attrs[thisAttrIdx];
- // Check if the attribute names are equal.
- if (attr.getName().equals(thisAttr.getName()))
- {
- // If the values are not equal, then return false immediately.
- // We should not compare version values here, since they are
- // a special case and have already been compared by a call to
- // isVersionInRange() before getting here; however, it is
- // possible for version to be mandatory, so make sure it is
- // present below.
- if (!attr.getValue().equals(thisAttr.getValue()))
- {
- return false;
- }
- found = true;
- }
- }
- // If the attribute was not found, then return false.
- if (!found)
- {
- return false;
- }
- }
-
- // Now, cycle through all attributes of this package and verify that
- // all mandatory attributes are present in the speceified package.
- for (int thisAttrIdx = 0; thisAttrIdx < m_attrs.length; thisAttrIdx++)
- {
- // Get current attribute for this package.
- R4Attribute thisAttr = m_attrs[thisAttrIdx];
-
- // If the attribute is mandatory, then make sure
- // the specified package has the attribute.
- if (thisAttr.isMandatory())
- {
- boolean found = false;
- for (int attrIdx = 0;
- (!found) && (attrIdx < pkg.m_attrs.length);
- attrIdx++)
- {
- // Get current attribute from specified package.
- R4Attribute attr = pkg.m_attrs[attrIdx];
-
- // Check if the attribute names are equal
- // and set found flag.
- if (thisAttr.getName().equals(attr.getName()))
- {
- found = true;
- }
- }
- // If not found, then return false.
- if (!found)
- {
- return false;
- }
- }
- }
-
- return true;
- }
public String toString()
{
- String msg = getId();
+ String msg = getName();
for (int i = 0; (m_directives != null) && (i < m_directives.length); i++)
{
msg = msg + " [" + m_directives[i].getName() + ":="+ m_directives[i].getValue() + "]";
@@ -471,164 +191,8 @@
}
}
- R4Package[] ips = (R4Package[])
+ R4Package[] pkgs = (R4Package[])
completeList.toArray(new R4Package[completeList.size()]);
- return ips;
- }
-
- public static R4Version[] parseVersionInterval(String interval)
- {
- // Check if the version is an interval.
- if (interval.indexOf(',') >= 0)
- {
- String s = interval.substring(1, interval.length() - 1);
- String vlo = s.substring(0, s.indexOf(','));
- String vhi = s.substring(s.indexOf(',') + 1, s.length());
- return new R4Version[] {
- new R4Version(vlo, (interval.charAt(0) == '[')),
- new R4Version(vhi, (interval.charAt(interval.length() - 1) == ']'))
- };
- }
- else
- {
- return new R4Version[] { new R4Version(interval, true) };
- }
- }
-
- //
- // The following substring-related code was lifted and modified
- // from the LDAP parser code.
- //
-
- private static String[] parseSubstring(String target)
- {
- List pieces = new ArrayList();
- StringBuffer ss = new StringBuffer();
- // int kind = SIMPLE; // assume until proven otherwise
- boolean wasStar = false; // indicates last piece was a star
- boolean leftstar = false; // track if the initial piece is a star
- boolean rightstar = false; // track if the final piece is a star
-
- int idx = 0;
-
- // We assume (sub)strings can contain leading and trailing blanks
-loop: for (;;)
- {
- if (idx >= target.length())
- {
- if (wasStar)
- {
- // insert last piece as "" to handle trailing star
- rightstar = true;
- }
- else
- {
- pieces.add(ss.toString());
- // accumulate the last piece
- // note that in the case of
- // (cn=); this might be
- // the string "" (!=null)
- }
- ss.setLength(0);
- break loop;
- }
-
- char c = target.charAt(idx++);
- if (c == '*')
- {
- if (wasStar)
- {
- // encountered two successive stars;
- // I assume this is illegal
- throw new IllegalArgumentException("Invalid filter string: " + target);
- }
- if (ss.length() > 0)
- {
- pieces.add(ss.toString()); // accumulate the pieces
- // between '*' occurrences
- }
- ss.setLength(0);
- // if this is a leading star, then track it
- if (pieces.size() == 0)
- {
- leftstar = true;
- }
- ss.setLength(0);
- wasStar = true;
- }
- else
- {
- wasStar = false;
- ss.append(c);
- }
- }
- if (leftstar || rightstar || pieces.size() > 1)
- {
- // insert leading and/or trailing "" to anchor ends
- if (rightstar)
- {
- pieces.add("");
- }
- if (leftstar)
- {
- pieces.add(0, "");
- }
- }
- return (String[]) pieces.toArray(new String[pieces.size()]);
- }
-
- private static boolean checkSubstring(String[] pieces, String s)
- {
- // Walk the pieces to match the string
- // There are implicit stars between each piece,
- // and the first and last pieces might be "" to anchor the match.
- // assert (pieces.length > 1)
- // minimal case is <string>*<string>
-
- boolean result = false;
- int len = pieces.length;
-
-loop: for (int i = 0; i < len; i++)
- {
- String piece = (String) pieces[i];
- int index = 0;
- if (i == len - 1)
- {
- // this is the last piece
- if (s.endsWith(piece))
- {
- result = true;
- }
- else
- {
- result = false;
- }
- break loop;
- }
- // initial non-star; assert index == 0
- else if (i == 0)
- {
- if (!s.startsWith(piece))
- {
- result = false;
- break loop;
- }
- }
- // assert i > 0 && i < len-1
- else
- {
- // Sure wish stringbuffer supported e.g. indexOf
- index = s.indexOf(piece, index);
- if (index < 0)
- {
- result = false;
- break loop;
- }
- }
- // start beyond the matching piece
- index += piece.length();
- }
-
- return result;
+ return pkgs;
}
}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
old mode 100755
new mode 100644
index 7c22675..ef6bfef
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,1619 +17,119 @@
package org.apache.felix.framework.searchpolicy;
import java.net.URL;
-import java.util.*;
-import org.apache.felix.framework.LogWrapper;
-import org.apache.felix.framework.util.SecurityManagerEx;
import org.apache.felix.moduleloader.*;
-import org.apache.felix.moduleloader.search.ResolveException;
-import org.apache.felix.moduleloader.search.ResolveListener;
-public class R4SearchPolicy implements SearchPolicy, ModuleListener
+public class R4SearchPolicy implements IR4SearchPolicy
{
- // Array of R4Package.
- public static final String EXPORTS_ATTR = "exports";
- // Array of R4Package.
- public static final String IMPORTS_ATTR = "imports";
- // Array of R4Package.
- public static final String DYNAMICIMPORTS_ATTR = "dynamicimports";
- // Array of R4Wire.
- public static final String WIRING_ATTR = "wiring";
- // Boolean.
- public static final String RESOLVED_ATTR = "resolved";
+ private R4SearchPolicyCore m_policyCore = null;
+ private IModule m_module = null;
- private LogWrapper m_logger = null;
- private ModuleManager m_mgr = null;
- private Map m_availPkgMap = new HashMap();
- private Map m_inUsePkgMap = new HashMap();
-
- // Listener-related instance variables.
- private static final ResolveListener[] m_emptyListeners = new ResolveListener[0];
- private ResolveListener[] m_listeners = m_emptyListeners;
-
- // Reusable empty arrays.
- public static final Module[] m_emptyModules = new Module[0];
- public static final R4Package[] m_emptyPackages = new R4Package[0];
- public static final R4Wire[] m_emptyWires = new R4Wire[0];
-
- // Re-usable security manager for accessing class context.
- private static SecurityManagerEx m_sm = new SecurityManagerEx();
-
- public R4SearchPolicy(LogWrapper logger)
+ public R4SearchPolicy(R4SearchPolicyCore policyCore, IModule module)
{
- m_logger = logger;
+ m_policyCore = policyCore;
+ m_module = module;
}
- public void setModuleManager(ModuleManager mgr)
- throws IllegalStateException
+ public Object[] definePackage(String name)
{
- if (m_mgr == null)
- {
- m_mgr = mgr;
- m_mgr.addModuleListener(this);
- }
- else
- {
- throw new IllegalStateException("Module manager is already initialized");
- }
+ return m_policyCore.definePackage(m_module, name);
}
- public Object[] definePackage(Module module, String pkgName)
- {
- R4Package pkg = R4SearchPolicy.getExportPackage(module, pkgName);
- if (pkg != null)
- {
- return new Object[] {
- pkgName, // Spec title.
- pkg.getVersionLow().toString(), // Spec version.
- "", // Spec vendor.
- "", // Impl title.
- "", // Impl version.
- "" // Impl vendor.
- };
- }
- return null;
- }
-
- public Class findClassBeforeModule(ClassLoader parent, Module module, String name)
+ public Class findClass(String name)
throws ClassNotFoundException
{
- // First, try to resolve the originating module.
- try
- {
- resolve(module);
- }
- catch (ResolveException ex)
- {
- // We do not use the resolve exception as the
- // cause of the exception, since this would
- // potentially leak internal module information.
- throw new ClassNotFoundException(
- name + ": cannot resolve package "
- + ex.getPackage() + ".");
- }
-
- // Get the package of the target class.
- String pkgName = Util.getClassPackage(name);
-
- // Load all "java.*" classes from parent class loader;
- // these packages cannot be provided by other bundles.
- if (pkgName.startsWith("java."))
- {
- return (parent == null) ? null : parent.loadClass(name);
- }
-
- // We delegate to the module's wires to find the class.
- R4Wire[] wires = getWiringAttr(module);
- for (int i = 0; i < wires.length; i++)
- {
- // Only check when the package of the class is
- // the same as the import package.
- if (wires[i].m_pkg.getId().equals(pkgName))
- {
- // Before delegating to the module class loader to satisfy
- // the class load, we must check the include/exclude filters
- // from the target package to make sure that the class is
- // actually visible. If the exporting module is the same as
- // the requesting module, then filtering is not performed
- // since a module has complete access to itself.
-// TODO: Determine if it is possible to modify Module Loader somehow
-// so that this check is done within the target module itself; it
-// doesn't totally make sense to do this check in the importing module.
- if (wires[i].m_module != module)
- {
- if (!wires[i].m_pkg.isIncluded(name))
- {
- throw new ClassNotFoundException(name);
- }
- }
-
- // Since the class is included, delegate to the exporting module.
- try
- {
- Class clazz = wires[i].m_module.getClassLoader().loadClassFromModule(name);
- if (clazz != null)
- {
- return clazz;
- }
- }
- catch (Throwable th)
- {
- // Not much we can do here.
- }
- throw new ClassNotFoundException(name);
- }
- }
-
- return null;
+ return m_policyCore.findClass(m_module, name);
}
- public Class findClassAfterModule(ClassLoader parent, Module module, String name)
- throws ClassNotFoundException
- {
- // At this point, the module's imports were searched and so was the
- // the module's own resources. Now we make an attempt to load the
- // class via a dynamic import, if possible.
- String pkgName = Util.getClassPackage(name);
- Module candidate = attemptDynamicImport(module, pkgName);
- // If the dynamic import was successful, then this initial
- // time we must directly return the result from dynamically
- // selected candidate's class loader, but for subsequent
- // requests for classes in the associated package will be
- // processed as part of normal static imports.
- if (candidate != null)
- {
- return candidate.getClassLoader().loadClass(name);
- }
-
- // At this point, the class could not be found by the bundle's static
- // or dynamic imports, nor its own resources. Before we throw
- // an exception, we will try to determine if the instigator of the
- // class load was a class from a bundle or not. This is necessary
- // because the specification mandates that classes on the class path
- // should be hidden (except for java.*), but it does allow for these
- // classes to be exposed by the system bundle as an export. However,
- // in some situations classes on the class path make the faulty
- // assumption that they can access everything on the class path from
- // every other class loader that they come in contact with. This is
- // not true if the class loader in question is from a bundle. Thus,
- // this code tries to detect that situation. If the class
- // instigating the class load was NOT from a bundle, then we will
- // make the assumption that the caller actually wanted to use the
- // parent class loader and we will delegate to it. If the class was
- // from a bundle, then we will enforce strict class loading rules
- // for the bundle and throw a class not found exception.
-
- // Get the class context to see the classes on the stack.
- Class[] classes = m_sm.getClassContext();
- // Start from 1 to skip inner class.
- for (int i = 1; i < classes.length; i++)
- {
- // Find the first class on the call stack that is neither
- // a class loader or Class itself, because we want to ignore
- // the calls to ClassLoader.loadClass() and Class.forName().
- if (!ClassLoader.class.isAssignableFrom(classes[i]) &&
- !Class.class.isAssignableFrom(classes[i]))
- {
- // If the instigating class was not from a bundle, then
- // delegate to the parent class loader. Otherwise, break
- // out of loop and throw an exception.
- if (!ModuleClassLoader.class.isInstance(classes[i].getClassLoader()))
- {
- return parent.loadClass(name);
- }
- break;
- }
- }
-
- throw new ClassNotFoundException(name);
- }
-
- public URL findResource(ClassLoader parent, Module module, String name)
+ public URL findResource(String name)
throws ResourceNotFoundException
{
- // First, try to resolve the originating module.
- try
- {
- resolve(module);
- }
- catch (ResolveException ex)
- {
- return null;
- }
-
- // Get the package of the target resource.
- String pkgName = Util.getResourcePackage(name);
-
- // Load all "java.*" resources from parent class loader;
- // these packages cannot be provided by other bundles.
- if (pkgName.startsWith("java."))
- {
- return (parent == null) ? null : parent.getResource(name);
- }
-
- // We delegate to the module's wires to find the resource.
- R4Wire[] wires = getWiringAttr(module);
- for (int i = 0; i < wires.length; i++)
- {
- // Only check when the package of the resource is
- // the same as the import package.
- if (wires[i].m_pkg.getId().equals(pkgName))
- {
- try
- {
- URL url = wires[i].m_module.getClassLoader().getResourceFromModule(name);
- if (url != null)
- {
- return url;
- }
- }
- catch (Throwable th)
- {
- // Not much we can do here.
- }
- throw new ResourceNotFoundException(name);
- }
- }
-
- // Check dynamic imports.
-// TODO: Dynamic imports should be searched after local sources.
- Module candidate = attemptDynamicImport(module, pkgName);
- // This initial time we must directly return the result from
- // the candidate's class loaders, but since the candidate was
- // added to the module's wiring attribute, subsequent class
- // loads from the same package will be handled in the normal
- // fashion for statically imported packaes.
- return (candidate == null)
- ? null : candidate.getClassLoader().getResource(name);
+ return m_policyCore.findResource(m_module, name);
}
- private Module attemptDynamicImport(Module module, String pkgName)
+ public String findLibrary(String name)
{
- Module candidate = null;
-
- // There is an overriding assumption here that a package is
- // never split across bundles. If a package can be split
- // across bundles, then this will fail.
-
- try
- {
- // Check the dynamic import specs for a match of
- // the target package.
- R4Package[] dynamics = getDynamicImportsAttr(module);
- R4Package pkgMatch = null;
- for (int i = 0; (pkgMatch == null) && (i < dynamics.length); i++)
- {
- // Star matches everything.
- if (dynamics[i].getId().equals("*"))
- {
- // Create a package instance without wildcard.
- pkgMatch = new R4Package(
- pkgName,
- dynamics[i].getDirectives(),
- dynamics[i].getAttributes());
- }
- // Packages ending in ".*" must match starting strings.
- else if (dynamics[i].getId().endsWith(".*"))
- {
- if (pkgName.regionMatches(
- 0, dynamics[i].getId(), 0, dynamics[i].getId().length() - 2))
- {
- // Create a package instance without wildcard.
- pkgMatch = new R4Package(
- pkgName,
- dynamics[i].getDirectives(),
- dynamics[i].getAttributes());
- }
- }
- // Or we can have a precise match.
- else
- {
- if (pkgName.equals(dynamics[i].getId()))
- {
- pkgMatch = dynamics[i];
- }
- }
- }
-
- // If the target package does not match any dynamically imported
- // packages or if the module is already wired for the target package,
- // then just return null. The module may be already wired to the target
- // package if the class being searched for does not actually exist.
- if ((pkgMatch == null) || (getWire(module, pkgMatch.getId()) != null))
- {
- return null;
- }
-
- // At this point, the target package has matched a dynamically
- // imported package spec. Now we must try to find a candidate
- // exporter for target package and add it to the module's set
- // of wires.
-
- // Lock module manager instance to ensure that nothing changes.
- synchronized (m_mgr)
- {
- // Try to add a new entry to the module's import attribute.
- // Select the first candidate that successfully resolves.
-
- // First check already resolved exports for a match.
- Module[] candidates = getCompatibleExporters(
- (Module[]) m_inUsePkgMap.get(pkgMatch.getId()), pkgMatch);
- // If there is an "in use" candidate, just take the first one.
- if (candidates.length > 0)
- {
- candidate = candidates[0];
- }
-
- // If there were no "in use" candidates, then try "available"
- // candidates.
- if (candidate == null)
- {
- candidates = getCompatibleExporters(
- (Module[]) m_availPkgMap.get(pkgMatch.getId()), pkgMatch);
- for (int candIdx = 0;
- (candidate == null) && (candIdx < candidates.length);
- candIdx++)
- {
- try
- {
- resolve(module);
- candidate = candidates[candIdx];
- }
- catch (ResolveException ex)
- {
- }
- }
- }
-
- // If we found a candidate, then add it to the module's
- // wiring attribute.
- if (candidate != null)
- {
- R4Wire[] wires = getWiringAttr(module);
- R4Wire[] newWires = new R4Wire[wires.length + 1];
- System.arraycopy(wires, 0, newWires, 0, wires.length);
- // Find the candidate's export package object and
- // use that for creating the wire; this is necessary
- // since it contains "uses" dependency information.
- newWires[wires.length] = new R4Wire(
- getExportPackage(candidate, pkgMatch.getId()), candidate);
- module.setAttribute(WIRING_ATTR, newWires);
-m_logger.log(LogWrapper.LOG_DEBUG, "WIRE: [" + module + "] " + newWires[wires.length]);
- }
- }
- }
- catch (Exception ex)
- {
- m_logger.log(LogWrapper.LOG_ERROR, "Unable to dynamically import package.", ex);
- }
-
- return candidate;
+ return m_policyCore.findLibrary(m_module, name);
}
- public Module[] getAvailableExporters(R4Package pkg)
+ public R4Export[] getExports()
{
- // Synchronized on the module manager to make sure that no
- // modules are added, removed, or resolved.
- synchronized (m_mgr)
- {
- return getCompatibleExporters((Module[]) m_availPkgMap.get(pkg.getId()), pkg);
- }
+ return m_policyCore.getExports(m_module);
}
- public Module[] getInUseExporters(R4Package pkg)
+ public void setExports(R4Export[] exports)
{
- // Synchronized on the module manager to make sure that no
- // modules are added, removed, or resolved.
- synchronized (m_mgr)
- {
- return getCompatibleExporters((Module[]) m_inUsePkgMap.get(pkg.getId()), pkg);
- }
+ m_policyCore.setExports(m_module, exports);
}
- public void resolve(Module rootModule)
- throws ResolveException
+ public R4Import[] getImports()
{
- // If the module is already resolved, then we can just return.
- if (getResolvedAttr(rootModule).booleanValue())
- {
- return;
- }
-
- // This variable maps an unresolved module to a list of resolver
- // nodes, where there is one resolver node for each import that
- // must be resolved. A resolver node contains the potential
- // candidates to resolve the import and the current selected
- // candidate index.
- Map resolverMap = new HashMap();
-
- // This map will be used to hold the final wires for all
- // resolved modules, which can then be used to fire resolved
- // events outside of the synchronized block.
- Map resolvedModuleWireMap = null;
-
- // Synchronize on the module manager, because we don't want
- // any modules being added or removed while we are in the
- // middle of this operation.
- synchronized (m_mgr)
- {
- // The first step is to populate the resolver map. This
- // will use the target module to populate the resolver map
- // with all potential modules that need to be resolved as a
- // result of resolving the target module. The key of the
- // map is a potential module to be resolved and the value is
- // a list of resolver nodes, one for each of the module's
- // imports, where each resolver node contains the potential
- // candidates for resolving the import. Not all modules in
- // this map will be resolved, only the target module and
- // any candidates selected to resolve its imports and the
- // transitive imports this implies.
- populateResolverMap(resolverMap, rootModule);
-
-//dumpResolverMap();
-
- // The next step is to use the resolver map to determine if
- // the class space for the root module is consistent. This
- // is an iterative process that transitively walks the "uses"
- // relationships of all currently selected potential candidates
- // for resolving import packages checking for conflicts. If a
- // conflict is found, it "increments" the configuration of
- // currently selected potential candidates and tests them again.
- // If this method returns, then it has found a consistent set
- // of candidates; otherwise, a resolve exception is thrown if
- // it exhausts all possible combinations and could not find a
- // consistent class space.
- findConsistentClassSpace(resolverMap, rootModule);
-
- // The final step is to create the wires for the root module and
- // transitively all modules that are to be resolved from the
- // selected candidates for resolving the root module's imports.
- // When this call returns, each module's wiring and resolved
- // attributes are set. The resulting wiring map is used below
- // to fire resolved events outside of the synchronized block.
- // The resolved module wire map maps a module to its array of
- // wires.
- resolvedModuleWireMap = createWires(resolverMap, rootModule);
-
-//dumpAvailablePackages();
-//dumpUsedPackages();
-
- } // End of synchronized block on module manager.
-
- // Fire resolved events for all resolved modules;
- // the resolved modules array will only be set if the resolve
- // was successful after the root module was resolved.
- if (resolvedModuleWireMap != null)
- {
- Iterator iter = resolvedModuleWireMap.entrySet().iterator();
- while (iter.hasNext())
- {
- fireModuleResolved((Module) ((Map.Entry) iter.next()).getKey());
- }
- }
+ return m_policyCore.getImports(m_module);
}
- private void populateResolverMap(Map resolverMap, Module module)
- throws ResolveException
+ public void setImports(R4Import[] imports)
{
- // Detect cycles.
- if (resolverMap.get(module) != null)
- {
- return;
- }
-
- // Map to hold the bundle's import packages
- // and their respective resolving candidates.
- List nodeList = new ArrayList();
-
- // Even though the node list is currently emptry, we
- // record it in the resolver map early so we can use
- // it to detect cycles.
- resolverMap.put(module, nodeList);
-
- // Loop through each import and calculate its resolving
- // set of candidates.
- R4Package[] imports = getImportsAttr(module);
- for (int impIdx = 0; impIdx < imports.length; impIdx++)
- {
- // Get the candidates from the "in use" and "available"
- // package maps. Candidates "in use" have higher priority
- // than "available" ones, so put the "in use" candidates
- // at the front of the list of candidates.
- Module[] inuse = getCompatibleExporters(
- (Module[]) m_inUsePkgMap.get(
- imports[impIdx].getId()), imports[impIdx]);
- Module[] available = getCompatibleExporters(
- (Module[]) m_availPkgMap.get(
- imports[impIdx].getId()), imports[impIdx]);
- Module[] candidates = new Module[inuse.length + available.length];
- System.arraycopy(inuse, 0, candidates, 0, inuse.length);
- System.arraycopy(available, 0, candidates, inuse.length, available.length);
-
- // If we have candidates, then we need to recursively populate
- // the resolver map with each of them.
- ResolveException rethrow = null;
- if (candidates.length > 0)
- {
- for (int candIdx = 0; candIdx < candidates.length; candIdx++)
- {
- try
- {
- // Only populate the resolver map with modules that
- // are not already resolved.
- if (!getResolvedAttr(candidates[candIdx]).booleanValue())
- {
- populateResolverMap(resolverMap, candidates[candIdx]);
- }
- }
- catch (ResolveException ex)
- {
- // If we received a resolve exception, then the
- // current candidate is not resolvable for some
- // reason and should be removed from the list of
- // candidates. For now, just null it.
- candidates[candIdx] = null;
- rethrow = ex;
- }
- }
-
- // Remove any nulled candidates to create the final list
- // of available candidates.
- candidates = shrinkModuleArray(candidates);
- }
-
- // If no candidates exist at this point, then throw a
- // resolve exception unless the import is optional.
- if ((candidates.length == 0) && !imports[impIdx].isOptional())
- {
- // If we have received an exception while trying to populate
- // the resolver map, rethrow that exception since it might
- // be useful. NOTE: This is not necessarily the "only"
- // correct exception, since it is possible that multiple
- // candidates were not resolvable, but it is better than
- // nothing.
- if (rethrow != null)
- {
- throw rethrow;
- }
- else
- {
- throw new ResolveException(
- "Unable to resolve.", module, imports[impIdx]);
- }
- }
- else if (candidates.length > 0)
- {
- nodeList.add(
- new ResolverNode(module, imports[impIdx], candidates));
- }
- }
+ m_policyCore.setImports(m_module, imports);
}
- /**
- * <p>
- * This method searches the resolver solution space for a consistent
- * set of modules to resolve all transitive imports that must be resolved
- * as a result of resolving the root module. A consistent set of modules
- * is one where the "uses" relationships of the exported packages for
- * the selected provider modules do not conflict with each other. A
- * conflict can occur when the constraints on two or more modules result
- * in multiple providers for the same package in the same class space.
- * </p>
- * @param resolverMap a map containing all potential modules that may need
- * to be resolved and the candidates to resolve them.
- * @param rootModule the module that is the root of the resolve operation.
- * @throws ResolveException if no consistent set of candidates can be
- * found to resolve the root module.
- **/
- private void findConsistentClassSpace(Map resolverMap, Module rootModule)
- throws ResolveException
+ public R4Import[] getDynamicImports()
{
- List resolverList = null;
-
- // Test the current set of candidates to determine if they
- // are consistent. Keep looping until we find a consistent
- // set or an exception is thrown.
- Map cycleMap = new HashMap();
- while (!isClassSpaceConsistent(resolverMap, rootModule, cycleMap))
- {
-m_logger.log(
- LogWrapper.LOG_DEBUG,
- "Constraint violation detected, will try to repair.");
-
- // The incrementCandidateConfiguration() method requires a
- // ordered access to the resolver map, so we will create
- // a reusable list once right here.
- if (resolverList == null)
- {
- resolverList = new ArrayList();
- for (Iterator iter = resolverMap.entrySet().iterator();
- iter.hasNext(); )
- {
- resolverList.add((List) ((Map.Entry) iter.next()).getValue());
- }
- }
-
- // Increment the candidate configuration so we can test again.
- incrementCandidateConfiguration(resolverList);
-
- // Clear the cycle map.
- cycleMap.clear();
- }
+ return m_policyCore.getDynamicImports(m_module);
}
- private boolean isClassSpaceConsistent(
- Map resolverMap, Module rootModule, Map cycleMap)
+ public void setDynamicImports(R4Import[] imports)
{
- // We do not need to verify that already resolved modules
- // have consistent class spaces because they should be
- // consistent by definition. Also, if the root module is
- // part of a cycle, then just assume it is true.
- if (getResolvedAttr(rootModule).booleanValue() ||
- (cycleMap.get(rootModule) != null))
- {
- return true;
- }
-
- // Add to cycle map for future reference.
- cycleMap.put(rootModule, rootModule);
-
- // Create an implicit "uses" constraint for every exported package
- // of the root module that is not also imported; uses constraints
- // for exported packages that are also imported will be taken
- // care of as part of normal import package processing.
- R4Package[] exports = (R4Package[]) getExportsAttr(rootModule);
- Map usesMap = new HashMap();
- for (int i = 0; i < exports.length; i++)
- {
- // Ignore exports that are also imported, since they
- // will be taken care of when verifying import constraints.
- if (getImportPackage(rootModule, exports[i].getId()) == null)
- {
- usesMap.put(exports[i].getId(), rootModule);
- }
- }
-
- // Loop through the current candidates for the module's imports
- // (available in the resolver node list of the resolver map) and
- // calculate the uses constraints for each of the currently
- // selected candidates for resolving the imports. Compare each
- // candidate's constraints to the existing constraints to check
- // for conflicts.
- List nodeList = (List) resolverMap.get(rootModule);
- for (int nodeIdx = 0; nodeIdx < nodeList.size(); nodeIdx++)
- {
- // Verify that the current candidate does not violate
- // any "uses" constraints of existing candidates by
- // calculating the candidate's transitive "uses" constraints
- // for the provided package and testing whether they
- // overlap with existing constraints.
-
- // First, get the resolver node.
- ResolverNode node = (ResolverNode) nodeList.get(nodeIdx);
-
- // Verify that the current candidate itself has a consistent
- // class space.
- if (!isClassSpaceConsistent(
- resolverMap, node.m_candidates[node.m_idx], cycleMap))
- {
- return false;
- }
-
- // Get the exported package from the current candidate that
- // will be used to resolve the root module's import.
- R4Package candidatePkg = getExportPackage(
- node.m_candidates[node.m_idx], node.m_pkg.getId());
-
- // Calculate the "uses" dependencies implied by the candidate's
- // exported package with respect to the currently selected
- // candidates in the resolver map.
- Map candUsesMap = calculateUsesDependencies(
- resolverMap,
- node.m_candidates[node.m_idx],
- candidatePkg,
- new HashMap());
-//System.out.println("MODULE " + rootModule + " USES " + usesMap);
-//System.out.println("CANDIDATE " + node.m_candidates[node.m_idx] + " USES " + candUsesMap);
-
- // Iterate through the root module's current set of transitive
- // "uses" constraints and compare them with the candidate's
- // transitive set of constraints.
- Iterator usesIter = candUsesMap.entrySet().iterator();
- while (usesIter.hasNext())
- {
- // If the candidate's uses constraints overlap with
- // the existing uses constraints, but refer to a
- // different provider, then the class space is not
- // consistent; thus, return false.
- Map.Entry entry = (Map.Entry) usesIter.next();
- if ((usesMap.get(entry.getKey()) != null) &&
- (usesMap.get(entry.getKey()) != entry.getValue()))
- {
- return false;
- }
- }
-
- // Since the current candidate's uses constraints did not
- // conflict with existing constraints, merge all constraints
- // and keep testing the remaining candidates for the other
- // imports of the root module.
- usesMap.putAll(candUsesMap);
- }
-
- return true;
+ m_policyCore.setDynamicImports(m_module, imports);
}
- private Map calculateUsesDependencies(
- Map resolverMap, Module module, R4Package exportPkg, Map usesMap)
+ public R4Library[] getLibraries()
{
-// TODO: CAN THIS BE OPTIMIZED?
-// TODO: IS THIS CYCLE CHECK CORRECT??
-// TODO: WHAT HAPPENS THERE ARE OVERLAPS WHEN CALCULATING USES??
-// MAKE AN EXAMPLE WHERE TWO DEPENDENCIES PROVIDE SAME PACKAGE.
- // Make sure we are not in a cycle.
- if (usesMap.get(exportPkg.getId()) != null)
- {
- return usesMap;
- }
-
- // The target package at least uses itself,
- // so add it to the uses map.
- usesMap.put(exportPkg.getId(), module);
-
- // Get the "uses" constraints for the target export
- // package and calculate the transitive uses constraints
- // of any used packages.
- String[] uses = exportPkg.getUses();
- List nodeList = (List) resolverMap.get(module);
-
- // We need to walk the transitive closure of "uses" relationships
- // for the current export package to calculate the entire set of
- // "uses" constraints.
- for (int usesIdx = 0; usesIdx < uses.length; usesIdx++)
- {
- // There are two possibilities at this point: 1) we are dealing
- // with an already resolved bundle or 2) we are dealing with a
- // bundle that has not yet been resolved. In case 1, there will
- // be no resolver node in the resolver map, so we just need to
- // examine the bundle directly to determine its exact constraints.
- // In case 2, there will be a resolver node in the resolver map,
- // so we will use that to determine the potential constraints of
- // potential candidate for resolving the import.
-
- // This is case 1, described in the comment above.
- if (nodeList == null)
- {
- // Get the actual exporter from the wire or if there
- // is no wire, then get the export is from the module
- // itself.
- R4Wire wire = getWire(module, uses[usesIdx]);
- if (wire != null)
- {
- usesMap = calculateUsesDependencies(
- resolverMap, wire.m_module, wire.m_pkg, usesMap);
- }
- else
- {
- exportPkg = getExportPackage(module, uses[usesIdx]);
- if (exportPkg != null)
- {
- usesMap = calculateUsesDependencies(
- resolverMap, module, exportPkg, usesMap);
- }
- }
- }
- // This is case 2, described in the comment above.
- else
- {
- // First, get the resolver node for the "used" package.
- ResolverNode node = null;
- for (int nodeIdx = 0;
- (node == null) && (nodeIdx < nodeList.size());
- nodeIdx++)
- {
- node = (ResolverNode) nodeList.get(nodeIdx);
- if (!node.m_pkg.getId().equals(uses[usesIdx]))
- {
- node = null;
- }
- }
-
- // If there is a resolver node for the "used" package,
- // then this means that the module imports the package
- // and we need to recursively add the constraints of
- // the potential exporting module.
- if (node != null)
- {
- usesMap = calculateUsesDependencies(
- resolverMap,
- node.m_candidates[node.m_idx],
- getExportPackage(node.m_candidates[node.m_idx], node.m_pkg.getId()),
- usesMap);
- }
- // If there was no resolver node for the "used" package,
- // then this means that the module exports the package
- // and we need to recursively add the constraints of this
- // other exported package of this module.
- else if (getExportPackage(module, uses[usesIdx]) != null)
- {
- usesMap = calculateUsesDependencies(
- resolverMap,
- module,
- getExportPackage(module, uses[usesIdx]),
- usesMap);
- }
- }
- }
-
- return usesMap;
+ return m_policyCore.getLibraries(m_module);
}
- /**
- * <p>
- * This method <i>increments</i> the current candidate configuration
- * in the specified resolver list, which contains resolver node lists
- * for all of the candidates for all of the imports that need to be
- * resolved. This method performs its function by treating the current
- * candidate index variable in each resolver node as part of a big
- * counter. In other words, it increments the least significant index.
- * If the index overflows it sets it back to zero and carries the
- * overflow to the next significant index and so on. Using this approach
- * it checks every possible combination for a solution.
- * </p>
- * <p>
- * This method is inefficient and a better approach is necessary. For
- * example, it does not take into account which imports are actually
- * being used, it just increments starting at the beginning of the list.
- * This means that it could be modifying candidates that are not relevant
- * to the current configuration and re-testing even though nothing has
- * really changed. It needs to be smarter.
- * </p>
- * @param resolverList an ordered list of resolver node lists for all
- * the candidates of the potential imports that need to be
- * resolved.
- * @throws ResolveException if the increment overflows the entire list,
- * signifying no consistent configurations exist.
- **/
- private void incrementCandidateConfiguration(List resolverList)
- throws ResolveException
+ public void setLibraries(R4Library[] libraries)
{
- for (int i = 0; i < resolverList.size(); i++)
- {
- List nodeList = (List) resolverList.get(i);
- for (int j = 0; j < nodeList.size(); j++)
- {
- ResolverNode node = (ResolverNode) nodeList.get(j);
- // See if we can increment the node, without overflowing
- // the candidate array bounds.
- if ((node.m_idx + 1) < node.m_candidates.length)
- {
- node.m_idx++;
- return;
- }
- // If the index will overflow the candidate array bounds,
- // then set the index back to zero and try to increment
- // the next candidate.
- else
- {
- node.m_idx = 0;
- }
- }
- }
- throw new ResolveException(
- "Unable to resolve due to constraint violation.", null, null);
+ m_policyCore.setLibraries(m_module, libraries);
}
- private Map createWires(Map resolverMap, Module rootModule)
+ public R4Wire[] getWires()
{
- Map resolvedModuleWireMap =
- populateWireMap(resolverMap, rootModule, new HashMap());
- Iterator iter = resolvedModuleWireMap.entrySet().iterator();
- while (iter.hasNext())
- {
- Map.Entry entry = (Map.Entry) iter.next();
- Module module = (Module) entry.getKey();
- R4Wire[] wires = (R4Wire[]) entry.getValue();
-
- // Set the module's resolved and wiring attribute.
- module.setAttribute(RESOLVED_ATTR, Boolean.TRUE);
- // Only add wires attribute if some exist; export
- // only modules may not have wires.
- if (wires.length > 0)
- {
- module.setAttribute(WIRING_ATTR, wires);
- }
-
- // Remove the wire's exporting module from the "available"
- // package map and put it into the "in use" package map;
- // these steps may be a no-op.
- for (int wireIdx = 0;
- (wires != null) && (wireIdx < wires.length);
- wireIdx++)
- {
-m_logger.log(LogWrapper.LOG_DEBUG, "WIRE: [" + module + "] " + wires[wireIdx]);
- // First remove the wire module from "available" package map.
- Module[] modules = (Module[]) m_availPkgMap.get(wires[wireIdx].m_pkg.getId());
- modules = removeModuleFromArray(modules, wires[wireIdx].m_module);
- m_availPkgMap.put(wires[wireIdx].m_pkg.getId(), modules);
-
- // Also remove any exported packages from the "available"
- // package map that are from the module associated with
- // the current wires where the exported packages were not
- // actually exported; an export may not be exported if
- // the module also imports the same package and was wired
- // to a different module. If the exported package is not
- // actually exported, then we just want to remove it
- // completely, since it cannot be used.
- if (wires[wireIdx].m_module != module)
- {
- modules = (Module[]) m_availPkgMap.get(wires[wireIdx].m_pkg.getId());
- modules = removeModuleFromArray(modules, module);
- m_availPkgMap.put(wires[wireIdx].m_pkg.getId(), modules);
- }
-
- // Add the module of the wire to the "in use" package map.
- modules = (Module[]) m_inUsePkgMap.get(wires[wireIdx].m_pkg.getId());
- modules = addModuleToArray(modules, wires[wireIdx].m_module);
- m_inUsePkgMap.put(wires[wireIdx].m_pkg.getId(), modules);
- }
- }
- return resolvedModuleWireMap;
+ return m_policyCore.getWires(m_module);
}
- private Map populateWireMap(Map resolverMap, Module module, Map wireMap)
+ public void setWires(R4Wire[] wires)
{
- // If the module is already resolved or it is part of
- // a cycle, then just return the wire map.
- if (getResolvedAttr(module).booleanValue() ||
- (wireMap.get(module) != null))
- {
- return wireMap;
- }
-
- List nodeList = (List) resolverMap.get(module);
- R4Wire[] wires = new R4Wire[nodeList.size()];
-
- // Put the module in the wireMap with an empty wire array;
- // we do this early so we can use it to detect cycles.
- wireMap.put(module, wires);
-
- // Loop through each resolver node and create a wire
- // for the selected candidate for the associated import.
- for (int nodeIdx = 0; nodeIdx < nodeList.size(); nodeIdx++)
- {
- // Get the import's associated resolver node.
- ResolverNode node = (ResolverNode) nodeList.get(nodeIdx);
-
- // Add the candidate to the list of wires.
- R4Package exportPkg =
- getExportPackage(node.m_candidates[node.m_idx], node.m_pkg.getId());
- wires[nodeIdx] = new R4Wire(exportPkg, node.m_candidates[node.m_idx]);
-
- // Create the wires for the selected candidate module.
- wireMap = populateWireMap(resolverMap, node.m_candidates[node.m_idx], wireMap);
- }
-
- return wireMap;
+ m_policyCore.setWires(m_module, wires);
}
-// TODO: REMOVE THESE DEBUG METHODS.
- private void dumpResolverMap(Map resolverMap)
+ public boolean isResolved()
{
- Iterator iter = resolverMap.entrySet().iterator();
- while (iter.hasNext())
- {
- Map.Entry entry = (Map.Entry) iter.next();
- ResolverNode node = (ResolverNode) entry.getValue();
- System.out.println("MODULE " + node.m_module + " IMPORT " + node.m_pkg);
- for (int i = 0; i < node.m_candidates.length; i++)
- {
- System.out.println("--> " + node.m_candidates[i]);
- }
- }
+ return m_policyCore.isResolved(m_module);
}
- private void dumpAvailablePackages()
+ public void setResolved(boolean resolved)
{
- synchronized (m_mgr)
- {
- System.out.println("AVAILABLE PACKAGES:");
- for (Iterator i = m_availPkgMap.entrySet().iterator(); i.hasNext(); )
- {
- Map.Entry entry = (Map.Entry) i.next();
- System.out.println(" " + entry.getKey());
- Module[] modules = (Module[]) entry.getValue();
- for (int j = 0; j < modules.length; j++)
- {
- System.out.println(" " + modules[j]);
- }
- }
- }
+ m_policyCore.setResolved(m_module, resolved);
}
- private void dumpUsedPackages()
+ public void resolve() throws ResolveException
{
- synchronized (m_mgr)
- {
- System.out.println("USED PACKAGES:");
- for (Iterator i = m_inUsePkgMap.entrySet().iterator(); i.hasNext(); )
- {
- Map.Entry entry = (Map.Entry) i.next();
- System.out.println(" " + entry.getKey());
- Module[] modules = (Module[]) entry.getValue();
- for (int j = 0; j < modules.length; j++)
- {
- System.out.println(" " + modules[j]);
- }
- }
- }
+ m_policyCore.resolve(m_module);
}
- /**
- * This method returns a list of modules that have an export
- * that is compatible with the given import identifier and version.
- * @param pkgMap a map of export packages to exporting modules.
- * @param target the target import package.
- * @return an array of modules that have compatible exports or <tt>null</tt>
- * if none are found.
- **/
- protected Module[] getCompatibleExporters(Module[] modules, R4Package target)
- {
- // Create list of compatible exporters.
- Module[] candidates = null;
- for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
- {
- // Get the modules export package for the target package.
- R4Package exportPkg = getExportPackage(modules[modIdx], target.getId());
- // If compatible, then add the candidate to the list.
- if ((exportPkg != null) && (exportPkg.doesSatisfy(target)))
- {
- candidates = addModuleToArray(candidates, modules[modIdx]);
- }
- }
-
- if (candidates == null)
- {
- return m_emptyModules;
- }
-
- return candidates;
- }
-
- public void moduleAdded(ModuleEvent event)
- {
- // When a module is added to the system, we need to initialize
- // its resolved and wiring attributes and add its exports to
- // the map of available exports.
-
- // Synchronize on the module manager, since we don't want any
- // bundles to be installed or removed.
- synchronized (m_mgr)
- {
- // Add wiring attribute.
- event.getModule().setAttribute(WIRING_ATTR, null);
- // Add resolved attribute.
- event.getModule().setAttribute(RESOLVED_ATTR, Boolean.FALSE);
- // Add exports to available package map.
- R4Package[] exports = getExportsAttr(event.getModule());
- for (int i = 0; i < exports.length; i++)
- {
- Module[] modules = (Module[]) m_availPkgMap.get(exports[i].getId());
-
- // We want to add the module into the list of available
- // exporters in sorted order (descending version and
- // ascending bundle identifier). Insert using a simple
- // binary search algorithm.
- if (modules == null)
- {
- modules = new Module[] { event.getModule() };
- }
- else
- {
- int top = 0, bottom = modules.length - 1, middle = 0;
- R4Version middleVersion = null;
- while (top <= bottom)
- {
- middle = (bottom - top) / 2 + top;
- middleVersion = getExportPackage(
- modules[middle], exports[i].getId()).getVersionLow();
- // Sort in reverse version order.
- int cmp = middleVersion.compareTo(exports[i].getVersionLow());
- if (cmp < 0)
- {
- bottom = middle - 1;
- }
- else if (cmp == 0)
- {
- // Sort further by ascending bundle ID.
- long middleId = getBundleIdFromModuleId(modules[middle].getId());
- long exportId = getBundleIdFromModuleId(event.getModule().getId());
- if (middleId < exportId)
- {
- top = middle + 1;
- }
- else
- {
- bottom = middle - 1;
- }
- }
- else
- {
- top = middle + 1;
- }
- }
-
- Module[] newMods = new Module[modules.length + 1];
- System.arraycopy(modules, 0, newMods, 0, top);
- System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
- newMods[top] = event.getModule();
- modules = newMods;
- }
-
- m_availPkgMap.put(exports[i].getId(), modules);
- }
- }
- }
-
- public void moduleReset(ModuleEvent event)
- {
- moduleRemoved(event);
- }
-
- public void moduleRemoved(ModuleEvent event)
- {
- // When a module is removed from the system, we need remove
- // its exports from the "in use" and "available" package maps.
-
- // Synchronize on the module manager, since we don't want any
- // bundles to be installed or removed.
- synchronized (m_mgr)
- {
- // Remove exports from package maps.
- R4Package[] pkgs = getExportsAttr(event.getModule());
- for (int i = 0; i < pkgs.length; i++)
- {
- // Remove from "available" package map.
- Module[] modules = (Module[]) m_availPkgMap.get(pkgs[i].getId());
- if (modules != null)
- {
- modules = removeModuleFromArray(modules, event.getModule());
- m_availPkgMap.put(pkgs[i].getId(), modules);
- }
- // Remove from "in use" package map.
- modules = (Module[]) m_inUsePkgMap.get(pkgs[i].getId());
- if (modules != null)
- {
- modules = removeModuleFromArray(modules, event.getModule());
- m_inUsePkgMap.put(pkgs[i].getId(), modules);
- }
- }
- }
- }
-
- // This is duplicated from BundleInfo and probably shouldn't be,
- // but its functionality is needed by the moduleAdded() callback.
- protected static long getBundleIdFromModuleId(String id)
- {
- try
- {
- String bundleId = (id.indexOf('.') >= 0)
- ? id.substring(0, id.indexOf('.')) : id;
- return Long.parseLong(bundleId);
- }
- catch (NumberFormatException ex)
- {
- return -1;
- }
- }
-
- //
- // Event handling methods for validation events.
- //
-
- /**
- * Adds a resolver listener to the search policy. Resolver
- * listeners are notified when a module is resolve and/or unresolved
- * by the search policy.
- * @param l the resolver listener to add.
- **/
public void addResolverListener(ResolveListener l)
{
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
-
- // Use the m_noListeners object as a lock.
- synchronized (m_emptyListeners)
- {
- // If we have no listeners, then just add the new listener.
- if (m_listeners == m_emptyListeners)
- {
- m_listeners = new ResolveListener[] { l };
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- ResolveListener[] newList = new ResolveListener[m_listeners.length + 1];
- System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
- newList[m_listeners.length] = l;
- m_listeners = newList;
- }
- }
+ m_policyCore.addResolverListener(l);
}
- /**
- * Removes a resolver listener to this search policy.
- * @param l the resolver listener to remove.
- **/
public void removeResolverListener(ResolveListener l)
{
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
-
- // Use the m_emptyListeners object as a lock.
- synchronized (m_emptyListeners)
- {
- // Try to find the instance in our list.
- int idx = -1;
- for (int i = 0; i < m_listeners.length; i++)
- {
- if (m_listeners[i].equals(l))
- {
- idx = i;
- break;
- }
- }
-
- // If we have the instance, then remove it.
- if (idx >= 0)
- {
- // If this is the last listener, then point to empty list.
- if (m_listeners.length == 1)
- {
- m_listeners = m_emptyListeners;
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- ResolveListener[] newList = new ResolveListener[m_listeners.length - 1];
- System.arraycopy(m_listeners, 0, newList, 0, idx);
- if (idx < newList.length)
- {
- System.arraycopy(m_listeners, idx + 1, newList, idx,
- newList.length - idx);
- }
- m_listeners = newList;
- }
- }
- }
+ m_policyCore.removeResolverListener(l);
}
- /**
- * Fires a validation event for the specified module.
- * @param module the module that was resolved.
- **/
- protected void fireModuleResolved(Module module)
+ public String toString()
{
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ResolveListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(m_mgr, module);
- }
- listeners[i].moduleResolved(event);
- }
- }
-
- /**
- * Fires an unresolved event for the specified module.
- * @param module the module that was unresolved.
- **/
- protected void fireModuleUnresolved(Module module)
- {
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ResolveListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(m_mgr, module);
- }
- listeners[i].moduleUnresolved(event);
- }
- }
-
- //
- // Static utility methods.
- //
-
- public static Boolean getResolvedAttr(Module m)
- {
- Boolean b =
- (Boolean) m.getAttribute(RESOLVED_ATTR);
- if (b == null)
- {
- b = Boolean.FALSE;
- }
- return b;
- }
-
- public static R4Package[] getExportsAttr(Module m)
- {
- R4Package[] attr =
- (R4Package[]) m.getAttribute(EXPORTS_ATTR);
- return (attr == null) ? m_emptyPackages : attr;
- }
-
- public static R4Package getExportPackage(Module m, String id)
- {
- R4Package[] pkgs = getExportsAttr(m);
- for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
- {
- if (pkgs[i].getId().equals(id))
- {
- return pkgs[i];
- }
- }
- return null;
- }
-
- public static R4Package[] getImportsAttr(Module m)
- {
- R4Package[] attr =
- (R4Package[]) m.getAttribute(IMPORTS_ATTR);
- return (attr == null) ? m_emptyPackages: attr;
- }
-
- public static R4Package getImportPackage(Module m, String id)
- {
- R4Package[] pkgs = getImportsAttr(m);
- for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
- {
- if (pkgs[i].getId().equals(id))
- {
- return pkgs[i];
- }
- }
- return null;
- }
-
- public static R4Package[] getDynamicImportsAttr(Module m)
- {
- R4Package[] attr =
- (R4Package[]) m.getAttribute(DYNAMICIMPORTS_ATTR);
- return (attr == null) ? m_emptyPackages: attr;
- }
-
- public static R4Package getDynamicImportPackage(Module m, String id)
- {
- R4Package[] pkgs = getDynamicImportsAttr(m);
- for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
- {
- if (pkgs[i].getId().equals(id))
- {
- return pkgs[i];
- }
- }
- return null;
- }
-
- public static R4Wire[] getWiringAttr(Module m)
- {
- R4Wire[] attr =
- (R4Wire[]) m.getAttribute(WIRING_ATTR);
- if (attr == null)
- {
- attr = m_emptyWires;
- }
- return attr;
- }
-
- public static R4Wire getWire(Module m, String id)
- {
- R4Wire[] wires = getWiringAttr(m);
- for (int i = 0; (wires != null) && (i < wires.length); i++)
- {
- if (wires[i].m_pkg.getId().equals(id))
- {
- return wires[i];
- }
- }
- return null;
- }
-
- public static boolean isModuleInArray(Module[] modules, Module m)
- {
- // Verify that the module is not already in the array.
- for (int i = 0; (modules != null) && (i < modules.length); i++)
- {
- if (modules[i] == m)
- {
- return true;
- }
- }
-
- return false;
- }
-
- public static Module[] addModuleToArray(Module[] modules, Module m)
- {
- // Verify that the module is not already in the array.
- for (int i = 0; (modules != null) && (i < modules.length); i++)
- {
- if (modules[i] == m)
- {
- return modules;
- }
- }
-
- if (modules != null)
- {
- Module[] newModules = new Module[modules.length + 1];
- System.arraycopy(modules, 0, newModules, 0, modules.length);
- newModules[modules.length] = m;
- modules = newModules;
- }
- else
- {
- modules = new Module[] { m };
- }
-
- return modules;
- }
-
- public static Module[] removeModuleFromArray(Module[] modules, Module m)
- {
- if (modules == null)
- {
- return m_emptyModules;
- }
-
- int idx = -1;
- for (int i = 0; i < modules.length; i++)
- {
- if (modules[i] == m)
- {
- idx = i;
- break;
- }
- }
-
- if (idx >= 0)
- {
- // If this is the module, then point to empty list.
- if ((modules.length - 1) == 0)
- {
- modules = m_emptyModules;
- }
- // Otherwise, we need to do some array copying.
- else
- {
- Module[] newModules= new Module[modules.length - 1];
- System.arraycopy(modules, 0, newModules, 0, idx);
- if (idx < newModules.length)
- {
- System.arraycopy(
- modules, idx + 1, newModules, idx, newModules.length - idx);
- }
- modules = newModules;
- }
- }
- return modules;
- }
-
-// TODO: INVESTIGATE GENERIC ARRAY GROWING/SHRINKING.
- private static R4Wire[] shrinkWireArray(R4Wire[] wires)
- {
- if (wires == null)
- {
- return m_emptyWires;
- }
-
- int count = 0;
- for (int i = 0; i < wires.length; i++)
- {
- if (wires[i] == null)
- {
- count++;
- }
- }
-
- if (count > 0)
- {
- R4Wire[] newWires = new R4Wire[wires.length - count];
- count = 0;
- for (int i = 0; i < wires.length; i++)
- {
- if (wires[i] != null)
- {
- newWires[count++] = wires[i];
- }
- }
- wires = newWires;
- }
-
- return wires;
- }
-
- private static Module[] shrinkModuleArray(Module[] modules)
- {
- if (modules == null)
- {
- return m_emptyModules;
- }
-
- int count = 0;
- for (int i = 0; i < modules.length; i++)
- {
- if (modules[i] == null)
- {
- count++;
- }
- }
-
- if (count > 0)
- {
- Module[] newModules = new Module[modules.length - count];
- count = 0;
- for (int i = 0; i < modules.length; i++)
- {
- if (modules[i] != null)
- {
- newModules[count++] = modules[i];
- }
- }
- modules = newModules;
- }
-
- return modules;
- }
-
- private static class ResolverNode
- {
- public Module m_module = null;
- public R4Package m_pkg = null;
- public Module[] m_candidates = null;
- public int m_idx = 0;
- public boolean m_visited = false;
- public ResolverNode(Module module, R4Package pkg, Module[] candidates)
- {
- m_module = module;
- m_pkg = pkg;
- m_candidates = candidates;
- if (getResolvedAttr(m_module).booleanValue())
- {
- m_visited = true;
- }
- }
+ return m_module.toString();
}
}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
new file mode 100755
index 0000000..e6d0d83
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -0,0 +1,1645 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import java.net.URL;
+import java.util.*;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.SecurityManagerEx;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.moduleloader.*;
+import org.osgi.framework.Version;
+
+public class R4SearchPolicyCore implements ModuleListener
+{
+ private Logger m_logger = null;
+ private IModuleFactory m_factory = null;
+ private Map m_availPkgMap = new HashMap();
+ private Map m_inUsePkgMap = new HashMap();
+ private Map m_moduleDataMap = new HashMap();
+
+ // Listener-related instance variables.
+ private static final ResolveListener[] m_emptyListeners = new ResolveListener[0];
+ private ResolveListener[] m_listeners = m_emptyListeners;
+
+ // Reusable empty array.
+ public static final IModule[] m_emptyModules = new IModule[0];
+
+ // Re-usable security manager for accessing class context.
+ private static SecurityManagerEx m_sm = new SecurityManagerEx();
+
+ public R4SearchPolicyCore(Logger logger)
+ {
+ m_logger = logger;
+ }
+
+ public IModuleFactory getModuleFactory()
+ {
+ return m_factory;
+ }
+
+ public void setModuleFactory(IModuleFactory factory)
+ throws IllegalStateException
+ {
+ if (m_factory == null)
+ {
+ m_factory = factory;
+ m_factory.addModuleListener(this);
+ }
+ else
+ {
+ throw new IllegalStateException("Module manager is already initialized");
+ }
+ }
+
+ public synchronized R4Export[] getExports(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? null : data.m_exports;
+ }
+
+ public synchronized void setExports(IModule module, R4Export[] exports)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_exports = exports;
+
+ // When a module is added and its exports are set, create an
+ // aggregated list of available exports to simplify later
+ // processing when resolving bundles.
+
+ // Add exports to available package map.
+ for (int i = 0; (exports != null) && (i < exports.length); i++)
+ {
+ IModule[] modules = (IModule[]) m_availPkgMap.get(exports[i].getName());
+
+ // We want to add the module into the list of available
+ // exporters in sorted order (descending version and
+ // ascending bundle identifier). Insert using a simple
+ // binary search algorithm.
+ if (modules == null)
+ {
+ modules = new IModule[] { module };
+ }
+ else
+ {
+ int top = 0, bottom = modules.length - 1, middle = 0;
+ Version middleVersion = null;
+ while (top <= bottom)
+ {
+ middle = (bottom - top) / 2 + top;
+ middleVersion = Util.getExportPackage(
+ modules[middle], exports[i].getName()).getVersion();
+ // Sort in reverse version order.
+ int cmp = middleVersion.compareTo(exports[i].getVersion());
+ if (cmp < 0)
+ {
+ bottom = middle - 1;
+ }
+ else if (cmp == 0)
+ {
+ // Sort further by ascending bundle ID.
+ long middleId = Util.getBundleIdFromModuleId(modules[middle].getId());
+ long exportId = Util.getBundleIdFromModuleId(module.getId());
+ if (middleId < exportId)
+ {
+ top = middle + 1;
+ }
+ else
+ {
+ bottom = middle - 1;
+ }
+ }
+ else
+ {
+ top = middle + 1;
+ }
+ }
+
+ IModule[] newMods = new IModule[modules.length + 1];
+ System.arraycopy(modules, 0, newMods, 0, top);
+ System.arraycopy(modules, top, newMods, top + 1, modules.length - top);
+ newMods[top] = module;
+ modules = newMods;
+ }
+
+ m_availPkgMap.put(exports[i].getName(), modules);
+ }
+ }
+
+ public synchronized R4Import[] getImports(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? null : data.m_imports;
+ }
+
+ public synchronized void setImports(IModule module, R4Import[] imports)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_imports = imports;
+ }
+
+ public synchronized R4Import[] getDynamicImports(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? null : data.m_dynamicImports;
+ }
+
+ public synchronized void setDynamicImports(IModule module, R4Import[] imports)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_dynamicImports = imports;
+ }
+
+ public synchronized R4Library[] getLibraries(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? null : data.m_libraries;
+ }
+
+ public synchronized void setLibraries(IModule module, R4Library[] libraries)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_libraries = libraries;
+ }
+
+ public synchronized R4Wire[] getWires(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? null : data.m_wires;
+ }
+
+ public synchronized void setWires(IModule module, R4Wire[] wires)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_wires = wires;
+ }
+
+ public synchronized boolean isResolved(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ return (data == null) ? false : data.m_resolved;
+ }
+
+ public synchronized void setResolved(IModule module, boolean resolved)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_resolved = resolved;
+ }
+
+ public Object[] definePackage(IModule module, String pkgName)
+ {
+ R4Package pkg = Util.getExportPackage(module, pkgName);
+ if (pkg != null)
+ {
+ return new Object[] {
+ pkgName, // Spec title.
+ pkg.getVersion().toString(), // Spec version.
+ "", // Spec vendor.
+ "", // Impl title.
+ "", // Impl version.
+ "" // Impl vendor.
+ };
+ }
+ return null;
+ }
+
+ public Class findClass(IModule module, String name)
+ throws ClassNotFoundException
+ {
+ // First, try to resolve the originating module.
+// TODO: Consider opimizing this call to resolve, since it is called
+// for each class load.
+ try
+ {
+ resolve(module);
+ }
+ catch (ResolveException ex)
+ {
+ // We do not use the resolve exception as the
+ // cause of the exception, since this would
+ // potentially leak internal module information.
+ throw new ClassNotFoundException(
+ name + ": cannot resolve package "
+ + ex.getPackage());
+ }
+
+ // Get the package of the target class.
+ String pkgName = Util.getClassPackage(name);
+
+ // Load all "java.*" classes from parent class loader;
+ // these packages cannot be provided by other bundles.
+ if (pkgName.startsWith("java."))
+ {
+ return this.getClass().getClassLoader().loadClass(name);
+ }
+
+ // Look in the module's imports.
+ Class clazz = findImportedClass(module, name, pkgName);
+
+ // If not found, try the module's own content.
+ if (clazz == null)
+ {
+ clazz = module.getContentLoader().getClass(name);
+
+ // If still not found, then try the module's dynamic imports.
+ if (clazz == null)
+ {
+ clazz = findDynamicallyImportedClass(module, name, pkgName);
+ }
+ }
+
+ if (clazz == null)
+ {
+ throw new ClassNotFoundException(name);
+ }
+
+ return clazz;
+ }
+
+ private Class findImportedClass(IModule module, String name, String pkgName)
+ throws ClassNotFoundException
+ {
+ // We delegate to the module's wires to find the class.
+ R4Wire[] wires = getWires(module);
+ for (int i = 0; (wires != null) && (i < wires.length); i++)
+ {
+ // If we find the class, then return it.
+ Class clazz = wires[i].getClass(name);
+ if (clazz != null)
+ {
+ return clazz;
+ }
+ }
+
+ return null;
+ }
+
+ private Class findDynamicallyImportedClass(
+ IModule module, String name, String pkgName)
+ throws ClassNotFoundException
+ {
+ // At this point, the module's imports were searched and so was the
+ // the module's content. Now we make an attempt to load the
+ // class via a dynamic import, if possible.
+ R4Wire wire = attemptDynamicImport(module, pkgName);
+
+ // If the dynamic import was successful, then this initial
+ // time we must directly return the result from dynamically
+ // created wire, but subsequent requests for classes in
+ // the associated package will be processed as part of
+ // normal static imports.
+ if (wire != null)
+ {
+ // If we find the class, then return it. Otherwise,
+ // throw an exception since the provider of the
+ // package did not have the class.
+ Class clazz = wire.getClass(name);
+ if (clazz != null)
+ {
+ return clazz;
+ }
+ else
+ {
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ // At this point, the class could not be found by the bundle's static
+ // or dynamic imports, nor its own resources. Before we throw
+ // an exception, we will try to determine if the instigator of the
+ // class load was a class from a bundle or not. This is necessary
+ // because the specification mandates that classes on the class path
+ // should be hidden (except for java.*), but it does allow for these
+ // classes to be exposed by the system bundle as an export. However,
+ // in some situations classes on the class path make the faulty
+ // assumption that they can access everything on the class path from
+ // every other class loader that they come in contact with. This is
+ // not true if the class loader in question is from a bundle. Thus,
+ // this code tries to detect that situation. If the class
+ // instigating the class load was NOT from a bundle, then we will
+ // make the assumption that the caller actually wanted to use the
+ // parent class loader and we will delegate to it. If the class was
+ // from a bundle, then we will enforce strict class loading rules
+ // for the bundle and throw a class not found exception.
+
+ // Get the class context to see the classes on the stack.
+ Class[] classes = m_sm.getClassContext();
+ // Start from 1 to skip security manager class.
+ for (int i = 1; i < classes.length; i++)
+ {
+ // Find the first class on the call stack that is neither
+ // a class loader or Class itself, because we want to ignore
+ // the calls to ClassLoader.loadClass() and Class.forName().
+ if (!ClassLoader.class.isAssignableFrom(classes[i]) &&
+ !Class.class.isAssignableFrom(classes[i]))
+ {
+ // If the instigating class was not from a bundle, then
+ // delegate to the parent class loader. Otherwise, break
+ // out of loop and throw an exception.
+ if (!ContentClassLoader.class.isInstance(classes[i].getClassLoader()))
+ {
+ return this.getClass().getClassLoader().loadClass(name);
+ }
+ break;
+ }
+ }
+
+ throw new ClassNotFoundException(name);
+ }
+
+ public URL findResource(IModule module, String name)
+ throws ResourceNotFoundException
+ {
+ // First, try to resolve the originating module.
+// TODO: Consider opimizing this call to resolve, since it is called
+// for each class load.
+ try
+ {
+ resolve(module);
+ }
+ catch (ResolveException ex)
+ {
+ // We do not use the resolve exception as the
+ // cause of the exception, since this would
+ // potentially leak internal module information.
+ throw new ResourceNotFoundException(
+ name + ": cannot resolve package "
+ + ex.getPackage());
+ }
+
+ // Get the package of the target class.
+ String pkgName = Util.getResourcePackage(name);
+
+ // Load all "java.*" classes from parent class loader;
+ // these packages cannot be provided by other bundles.
+ if (pkgName.startsWith("java."))
+ {
+ return this.getClass().getClassLoader().getResource(name);
+ }
+
+ // Look in the module's imports.
+ URL url = findImportedResource(module, name);
+
+ // If not found, try the module's own content.
+ if (url == null)
+ {
+ url = module.getContentLoader().getResource(name);
+
+ // If still not found, then try the module's dynamic imports.
+ if (url == null)
+ {
+ url = findDynamicallyImportedResource(module, name, pkgName);
+ }
+ }
+
+ if (url == null)
+ {
+ throw new ResourceNotFoundException(name);
+ }
+
+ return url;
+ }
+
+ private URL findImportedResource(IModule module, String name)
+ throws ResourceNotFoundException
+ {
+ // We delegate to the module's wires to find the class.
+ R4Wire[] wires = getWires(module);
+ for (int i = 0; (wires != null) && (i < wires.length); i++)
+ {
+ // If we find the resource, then return it.
+ URL url = wires[i].getResource(name);
+ if (url != null)
+ {
+ return url;
+ }
+ }
+
+ return null;
+ }
+
+ private URL findDynamicallyImportedResource(
+ IModule module, String name, String pkgName)
+ throws ResourceNotFoundException
+ {
+ // At this point, the module's imports were searched and so was the
+ // the module's content. Now we make an attempt to load the
+ // class via a dynamic import, if possible.
+ R4Wire wire = attemptDynamicImport(module, pkgName);
+
+ // If the dynamic import was successful, then this initial
+ // time we must directly return the result from dynamically
+ // created wire, but subsequent requests for resources in
+ // the associated package will be processed as part of
+ // normal static imports.
+ if (wire != null)
+ {
+ // If we find the class, then return it. Otherwise,
+ // throw an exception since the provider of the
+ // package did not have the class.
+ URL url = wire.getResource(name);
+ if (url != null)
+ {
+ return url;
+ }
+ else
+ {
+ throw new ResourceNotFoundException(name);
+ }
+ }
+
+ // At this point, the resource could not be found by the bundle's static
+ // or dynamic imports, nor its own resources. Before we throw
+ // an exception, we will try to determine if the instigator of the
+ // resource load was a class from a bundle or not. This is necessary
+ // because the specification mandates that classes on the class path
+ // should be hidden (except for java.*), but it does allow for these
+ // classes to be exposed by the system bundle as an export. However,
+ // in some situations classes on the class path make the faulty
+ // assumption that they can access everything on the class path from
+ // every other class loader that they come in contact with. This is
+ // not true if the class loader in question is from a bundle. Thus,
+ // this code tries to detect that situation. If the class
+ // instigating the resource load was NOT from a bundle, then we will
+ // make the assumption that the caller actually wanted to use the
+ // parent class loader and we will delegate to it. If the class was
+ // from a bundle, then we will enforce strict class loading rules
+ // for the bundle and throw a resource not found exception.
+
+ // Get the class context to see the classes on the stack.
+ Class[] classes = m_sm.getClassContext();
+ // Start from 1 to skip security manager class.
+ for (int i = 1; i < classes.length; i++)
+ {
+ // Find the first class on the call stack that is neither
+ // a class loader or Class itself, because we want to ignore
+ // the calls to ClassLoader.loadClass() and Class.forName().
+ if (!ClassLoader.class.isAssignableFrom(classes[i]) &&
+ !Class.class.isAssignableFrom(classes[i]))
+ {
+ // If the instigating class was not from a bundle, then
+ // delegate to the parent class loader. Otherwise, break
+ // out of loop and throw an exception.
+ if (!ContentClassLoader.class.isInstance(classes[i].getClassLoader()))
+ {
+ return this.getClass().getClassLoader().getResource(name);
+ }
+ break;
+ }
+ }
+
+ throw new ResourceNotFoundException(name);
+ }
+
+ private R4Wire attemptDynamicImport(IModule module, String pkgName)
+ {
+ R4Wire wire = null;
+ IModule candidate = null;
+
+ // There is an overriding assumption here that a package is
+ // never split across bundles. If a package can be split
+ // across bundles, then this will fail.
+
+ try
+ {
+ // Check the dynamic import specs for a match of
+ // the target package.
+ R4Import[] dynamics = getDynamicImports(module);
+ R4Import impMatch = null;
+ for (int i = 0;
+ (impMatch == null) && (dynamics != null) && (i < dynamics.length);
+ i++)
+ {
+ // Star matches everything.
+ if (dynamics[i].getName().equals("*"))
+ {
+ // Create a package instance without wildcard.
+ impMatch = new R4Import(
+ pkgName,
+ dynamics[i].getDirectives(),
+ dynamics[i].getAttributes());
+ }
+ // Packages ending in ".*" must match starting strings.
+ else if (dynamics[i].getName().endsWith(".*"))
+ {
+ if (pkgName.regionMatches(
+ 0, dynamics[i].getName(), 0, dynamics[i].getName().length() - 2))
+ {
+ // Create a package instance without wildcard.
+ impMatch = new R4Import(
+ pkgName,
+ dynamics[i].getDirectives(),
+ dynamics[i].getAttributes());
+ }
+ }
+ // Or we can have a precise match.
+ else
+ {
+ if (pkgName.equals(dynamics[i].getName()))
+ {
+ impMatch = dynamics[i];
+ }
+ }
+ }
+
+ // If the target package does not match any dynamically imported
+ // packages or if the module is already wired for the target package,
+ // then just return null. The module may be already wired to the target
+ // package if the class being searched for does not actually exist.
+ if ((impMatch == null) || (Util.getWire(module, impMatch.getName()) != null))
+ {
+ return null;
+ }
+
+ // At this point, the target package has matched a dynamically
+ // imported package spec. Now we must try to find a candidate
+ // exporter for target package and add it to the module's set
+ // of wires.
+
+ // Lock module manager instance to ensure that nothing changes.
+ synchronized (m_factory)
+ {
+ // Try to add a new entry to the module's import attribute.
+ // Select the first candidate that successfully resolves.
+
+ // First check already resolved exports for a match.
+ IModule[] candidates = getCompatibleExporters(
+ (IModule[]) m_inUsePkgMap.get(impMatch.getName()), impMatch);
+ // If there is an "in use" candidate, just take the first one.
+ if (candidates.length > 0)
+ {
+ candidate = candidates[0];
+ }
+
+ // If there were no "in use" candidates, then try "available"
+ // candidates.
+ if (candidate == null)
+ {
+ candidates = getCompatibleExporters(
+ (IModule[]) m_availPkgMap.get(impMatch.getName()), impMatch);
+ for (int candIdx = 0;
+ (candidate == null) && (candIdx < candidates.length);
+ candIdx++)
+ {
+ try
+ {
+ resolve(module);
+ candidate = candidates[candIdx];
+ }
+ catch (ResolveException ex)
+ {
+ }
+ }
+ }
+
+ // If we found a candidate, then add it to the module's
+ // wiring attribute.
+ if (candidate != null)
+ {
+ R4Wire[] wires = getWires(module);
+ R4Wire[] newWires = null;
+ if (wires == null)
+ {
+ newWires = new R4Wire[1];
+ }
+ else
+ {
+ newWires = new R4Wire[wires.length + 1];
+ System.arraycopy(wires, 0, newWires, 0, wires.length);
+ }
+ // Find the candidate's export package object and
+ // use that for creating the wire; this is necessary
+ // since it contains "uses" dependency information.
+ wire = new R4Wire(
+ module, candidate,
+ Util.getExportPackage(candidate, impMatch.getName()));
+ newWires[wires.length] = wire;
+ setWires(module, newWires);
+m_logger.log(Logger.LOG_DEBUG, "WIRE: [" + module + "] " + newWires[wires.length]);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Unable to dynamically import package.", ex);
+ }
+
+ return wire;
+ }
+
+ public String findLibrary(IModule module, String name)
+ {
+ // Remove leading slash, if present.
+ if (name.startsWith("/"))
+ {
+ name = name.substring(1);
+ }
+
+ // TODO: This "matching" algorithm does not fully
+ // match the spec and should be improved.
+ R4Library[] libs = getLibraries(module);
+ for (int i = 0; (libs != null) && (i < libs.length); i++)
+ {
+ String path = libs[i].getPath(name);
+ if (path != null)
+ {
+ return path;
+ }
+ }
+
+ return null;
+ }
+
+ public IModule[] getAvailableExporters(R4Import pkg)
+ {
+ // Synchronized on the module manager to make sure that no
+ // modules are added, removed, or resolved.
+ synchronized (m_factory)
+ {
+ return getCompatibleExporters((IModule[]) m_availPkgMap.get(pkg.getName()), pkg);
+ }
+ }
+
+ public IModule[] getInUseExporters(R4Import pkg)
+ {
+ // Synchronized on the module manager to make sure that no
+ // modules are added, removed, or resolved.
+ synchronized (m_factory)
+ {
+ return getCompatibleExporters((IModule[]) m_inUsePkgMap.get(pkg.getName()), pkg);
+ }
+ }
+
+ public void resolve(IModule rootModule)
+ throws ResolveException
+ {
+ // If the module is already resolved, then we can just return.
+ if (isResolved(rootModule))
+ {
+ return;
+ }
+
+ // This variable maps an unresolved module to a list of resolver
+ // nodes, where there is one resolver node for each import that
+ // must be resolved. A resolver node contains the potential
+ // candidates to resolve the import and the current selected
+ // candidate index.
+ Map resolverMap = new HashMap();
+
+ // This map will be used to hold the final wires for all
+ // resolved modules, which can then be used to fire resolved
+ // events outside of the synchronized block.
+ Map resolvedModuleWireMap = null;
+
+ // Synchronize on the module manager, because we don't want
+ // any modules being added or removed while we are in the
+ // middle of this operation.
+ synchronized (m_factory)
+ {
+ // The first step is to populate the resolver map. This
+ // will use the target module to populate the resolver map
+ // with all potential modules that need to be resolved as a
+ // result of resolving the target module. The key of the
+ // map is a potential module to be resolved and the value is
+ // a list of resolver nodes, one for each of the module's
+ // imports, where each resolver node contains the potential
+ // candidates for resolving the import. Not all modules in
+ // this map will be resolved, only the target module and
+ // any candidates selected to resolve its imports and the
+ // transitive imports this implies.
+ populateResolverMap(resolverMap, rootModule);
+
+ // The next step is to use the resolver map to determine if
+ // the class space for the root module is consistent. This
+ // is an iterative process that transitively walks the "uses"
+ // relationships of all currently selected potential candidates
+ // for resolving import packages checking for conflicts. If a
+ // conflict is found, it "increments" the configuration of
+ // currently selected potential candidates and tests them again.
+ // If this method returns, then it has found a consistent set
+ // of candidates; otherwise, a resolve exception is thrown if
+ // it exhausts all possible combinations and could not find a
+ // consistent class space.
+ findConsistentClassSpace(resolverMap, rootModule);
+
+ // The final step is to create the wires for the root module and
+ // transitively all modules that are to be resolved from the
+ // selected candidates for resolving the root module's imports.
+ // When this call returns, each module's wiring and resolved
+ // attributes are set. The resulting wiring map is used below
+ // to fire resolved events outside of the synchronized block.
+ // The resolved module wire map maps a module to its array of
+ // wires.
+ resolvedModuleWireMap = createWires(resolverMap, rootModule);
+
+//dumpAvailablePackages();
+//dumpUsedPackages();
+
+ } // End of synchronized block on module manager.
+
+ // Fire resolved events for all resolved modules;
+ // the resolved modules array will only be set if the resolve
+ // was successful after the root module was resolved.
+ if (resolvedModuleWireMap != null)
+ {
+ Iterator iter = resolvedModuleWireMap.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ fireModuleResolved((IModule) ((Map.Entry) iter.next()).getKey());
+ }
+ }
+ }
+
+ private void populateResolverMap(Map resolverMap, IModule module)
+ throws ResolveException
+ {
+ // Detect cycles.
+ if (resolverMap.get(module) != null)
+ {
+ return;
+ }
+ // Map to hold the module's import packages
+ // and their respective resolving candidates.
+ List nodeList = new ArrayList();
+
+ // Even though the node list is currently empty, we
+ // record it in the resolver map early so we can use
+ // it to detect cycles.
+ resolverMap.put(module, nodeList);
+
+ // Loop through each import and calculate its resolving
+ // set of candidates.
+ R4Import[] imports = getImports(module);
+ for (int impIdx = 0; (imports != null) && (impIdx < imports.length); impIdx++)
+ {
+ // Get the candidates from the "in use" and "available"
+ // package maps. Candidates "in use" have higher priority
+ // than "available" ones, so put the "in use" candidates
+ // at the front of the list of candidates.
+ IModule[] inuse = getCompatibleExporters(
+ (IModule[]) m_inUsePkgMap.get(
+ imports[impIdx].getName()), imports[impIdx]);
+ IModule[] available = getCompatibleExporters(
+ (IModule[]) m_availPkgMap.get(
+ imports[impIdx].getName()), imports[impIdx]);
+ IModule[] candidates = new IModule[inuse.length + available.length];
+ System.arraycopy(inuse, 0, candidates, 0, inuse.length);
+ System.arraycopy(available, 0, candidates, inuse.length, available.length);
+
+ // If we have candidates, then we need to recursively populate
+ // the resolver map with each of them.
+ ResolveException rethrow = null;
+ if (candidates.length > 0)
+ {
+ for (int candIdx = 0; candIdx < candidates.length; candIdx++)
+ {
+ try
+ {
+ // Only populate the resolver map with modules that
+ // are not already resolved.
+ if (!isResolved(candidates[candIdx]))
+ {
+ populateResolverMap(resolverMap, candidates[candIdx]);
+ }
+ }
+ catch (ResolveException ex)
+ {
+ // If we received a resolve exception, then the
+ // current candidate is not resolvable for some
+ // reason and should be removed from the list of
+ // candidates. For now, just null it.
+ candidates[candIdx] = null;
+ rethrow = ex;
+ }
+ }
+
+ // Remove any nulled candidates to create the final list
+ // of available candidates.
+ candidates = shrinkModuleArray(candidates);
+ }
+
+ // If no candidates exist at this point, then throw a
+ // resolve exception unless the import is optional.
+ if ((candidates.length == 0) && !imports[impIdx].isOptional())
+ {
+ // If we have received an exception while trying to populate
+ // the resolver map, rethrow that exception since it might
+ // be useful. NOTE: This is not necessarily the "only"
+ // correct exception, since it is possible that multiple
+ // candidates were not resolvable, but it is better than
+ // nothing.
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+ else
+ {
+ throw new ResolveException(
+ "Unable to resolve.", module, imports[impIdx]);
+ }
+ }
+ else if (candidates.length > 0)
+ {
+ nodeList.add(
+ new ResolverNode(module, imports[impIdx], candidates));
+ }
+ }
+ }
+
+
+// TODO: REMOVE THESE DEBUG METHODS.
+ private void dumpAvailablePackages()
+ {
+ synchronized (this)
+ {
+ System.out.println("AVAILABLE PACKAGES:");
+ for (Iterator i = m_availPkgMap.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ System.out.println(" " + entry.getKey());
+ IModule[] modules = (IModule[]) entry.getValue();
+ for (int j = 0; j < modules.length; j++)
+ {
+ System.out.println(" " + modules[j]);
+ }
+ }
+ }
+ }
+
+ private void dumpUsedPackages()
+ {
+ synchronized (this)
+ {
+ System.out.println("USED PACKAGES:");
+ for (Iterator i = m_inUsePkgMap.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ System.out.println(" " + entry.getKey());
+ IModule[] modules = (IModule[]) entry.getValue();
+ for (int j = 0; j < modules.length; j++)
+ {
+ System.out.println(" " + modules[j]);
+ }
+ }
+ }
+ }
+
+ private IModule[] getCompatibleExporters(IModule[] modules, R4Import target)
+ {
+ // Create list of compatible exporters.
+ IModule[] candidates = null;
+ for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+ {
+ // Get the modules export package for the target package.
+ R4Export export = Util.getExportPackage(modules[modIdx], target.getName());
+ // If compatible, then add the candidate to the list.
+ if ((export != null) && (target.isSatisfied(export)))
+ {
+ candidates = addModuleToArray(candidates, modules[modIdx]);
+ }
+ }
+ if (candidates == null)
+ {
+ return m_emptyModules;
+ }
+ return candidates;
+ }
+
+ private void findConsistentClassSpace(Map resolverMap, IModule rootModule)
+ throws ResolveException
+ {
+ List resolverList = null;
+
+ // Test the current set of candidates to determine if they
+ // are consistent. Keep looping until we find a consistent
+ // set or an exception is thrown.
+ Map cycleMap = new HashMap();
+ while (!isClassSpaceConsistent(resolverMap, rootModule, cycleMap))
+ {
+m_logger.log(
+ Logger.LOG_DEBUG,
+ "Constraint violation detected, will try to repair.");
+
+ // The incrementCandidateConfiguration() method requires an
+ // ordered access to the resolver map, so we will create
+ // a reusable list once right here.
+ if (resolverList == null)
+ {
+ resolverList = new ArrayList();
+ for (Iterator iter = resolverMap.entrySet().iterator();
+ iter.hasNext(); )
+ {
+ resolverList.add((List) ((Map.Entry) iter.next()).getValue());
+ }
+ }
+
+ // Increment the candidate configuration so we can test again.
+ incrementCandidateConfiguration(resolverList);
+
+ // Clear the cycle map.
+ cycleMap.clear();
+ }
+ }
+
+ private boolean isClassSpaceConsistent(
+ Map resolverMap, IModule rootModule, Map cycleMap)
+ {
+ // We do not need to verify that already resolved modules
+ // have consistent class spaces because they should be
+ // consistent by definition. Also, if the root module is
+ // part of a cycle, then just assume it is true.
+ if (isResolved(rootModule) || (cycleMap.get(rootModule) != null))
+ {
+ return true;
+ }
+
+ // Add to cycle map for future reference.
+ cycleMap.put(rootModule, rootModule);
+
+ // Create an implicit "uses" constraint for every exported package
+ // of the root module that is not also imported; uses constraints
+ // for exported packages that are also imported will be taken
+ // care of as part of normal import package processing.
+ R4Export[] exports = getExports(rootModule);
+ Map usesMap = new HashMap();
+ for (int i = 0; (exports != null) && (i < exports.length); i++)
+ {
+ // Ignore exports that are also imported, since they
+ // will be taken care of when verifying import constraints.
+ if (Util.getImportPackage(rootModule, exports[i].getName()) == null)
+ {
+ usesMap.put(exports[i].getName(), rootModule);
+ }
+ }
+
+ // Loop through the current candidates for the module's imports
+ // (available in the resolver node list of the resolver map) and
+ // calculate the uses constraints for each of the currently
+ // selected candidates for resolving the imports. Compare each
+ // candidate's constraints to the existing constraints to check
+ // for conflicts.
+ List nodeList = (List) resolverMap.get(rootModule);
+ for (int nodeIdx = 0; nodeIdx < nodeList.size(); nodeIdx++)
+ {
+ // Verify that the current candidate does not violate
+ // any "uses" constraints of existing candidates by
+ // calculating the candidate's transitive "uses" constraints
+ // for the provided package and testing whether they
+ // overlap with existing constraints.
+
+ // First, get the resolver node.
+ ResolverNode node = (ResolverNode) nodeList.get(nodeIdx);
+
+ // Verify that the current candidate itself has a consistent
+ // class space.
+ if (!isClassSpaceConsistent(
+ resolverMap, node.m_candidates[node.m_idx], cycleMap))
+ {
+ return false;
+ }
+
+ // Get the exported package from the current candidate that
+ // will be used to resolve the root module's import.
+ R4Export candidatePkg = Util.getExportPackage(
+ node.m_candidates[node.m_idx], node.m_import.getName());
+
+ // Calculate the "uses" dependencies implied by the candidate's
+ // exported package with respect to the currently selected
+ // candidates in the resolver map.
+ Map candUsesMap = calculateUsesDependencies(
+ resolverMap,
+ node.m_candidates[node.m_idx],
+ candidatePkg,
+ new HashMap());
+//System.out.println("MODULE " + rootModule + " USES " + usesMap);
+//System.out.println("CANDIDATE " + node.m_candidates[node.m_idx] + " USES " + candUsesMap);
+
+ // Iterate through the root module's current set of transitive
+ // "uses" constraints and compare them with the candidate's
+ // transitive set of constraints.
+ Iterator usesIter = candUsesMap.entrySet().iterator();
+ while (usesIter.hasNext())
+ {
+ // If the candidate's uses constraints overlap with
+ // the existing uses constraints, but refer to a
+ // different provider, then the class space is not
+ // consistent; thus, return false.
+ Map.Entry entry = (Map.Entry) usesIter.next();
+ if ((usesMap.get(entry.getKey()) != null) &&
+ (usesMap.get(entry.getKey()) != entry.getValue()))
+ {
+ return false;
+ }
+ }
+
+ // Since the current candidate's uses constraints did not
+ // conflict with existing constraints, merge all constraints
+ // and keep testing the remaining candidates for the other
+ // imports of the root module.
+ usesMap.putAll(candUsesMap);
+ }
+
+ return true;
+ }
+
+ private Map calculateUsesDependencies(
+ Map resolverMap, IModule module, R4Export export, Map usesMap)
+ {
+// TODO: CAN THIS BE OPTIMIZED?
+// TODO: IS THIS CYCLE CHECK CORRECT??
+// TODO: WHAT HAPPENS THERE ARE OVERLAPS WHEN CALCULATING USES??
+// MAKE AN EXAMPLE WHERE TWO DEPENDENCIES PROVIDE SAME PACKAGE.
+ // Make sure we are not in a cycle.
+ if (usesMap.get(export.getName()) != null)
+ {
+ return usesMap;
+ }
+
+ // The target package at least uses itself,
+ // so add it to the uses map.
+ usesMap.put(export.getName(), module);
+
+ // Get the "uses" constraints for the target export
+ // package and calculate the transitive uses constraints
+ // of any used packages.
+ String[] uses = export.getUses();
+ List nodeList = (List) resolverMap.get(module);
+
+ // We need to walk the transitive closure of "uses" relationships
+ // for the current export package to calculate the entire set of
+ // "uses" constraints.
+ for (int usesIdx = 0; usesIdx < uses.length; usesIdx++)
+ {
+ // There are two possibilities at this point: 1) we are dealing
+ // with an already resolved bundle or 2) we are dealing with a
+ // bundle that has not yet been resolved. In case 1, there will
+ // be no resolver node in the resolver map, so we just need to
+ // examine the bundle directly to determine its exact constraints.
+ // In case 2, there will be a resolver node in the resolver map,
+ // so we will use that to determine the potential constraints of
+ // potential candidate for resolving the import.
+
+ // This is case 1, described in the comment above.
+ if (nodeList == null)
+ {
+ // Get the actual exporter from the wire or if there
+ // is no wire, then get the export is from the module
+ // itself.
+ R4Wire wire = Util.getWire(module, uses[usesIdx]);
+ if (wire != null)
+ {
+ usesMap = calculateUsesDependencies(
+ resolverMap, wire.getExportingModule(), wire.getExport(), usesMap);
+ }
+ else
+ {
+ export = Util.getExportPackage(module, uses[usesIdx]);
+ if (export != null)
+ {
+ usesMap = calculateUsesDependencies(
+ resolverMap, module, export, usesMap);
+ }
+ }
+ }
+ // This is case 2, described in the comment above.
+ else
+ {
+ // First, get the resolver node for the "used" package.
+ ResolverNode node = null;
+ for (int nodeIdx = 0;
+ (node == null) && (nodeIdx < nodeList.size());
+ nodeIdx++)
+ {
+ node = (ResolverNode) nodeList.get(nodeIdx);
+ if (!node.m_import.getName().equals(uses[usesIdx]))
+ {
+ node = null;
+ }
+ }
+
+ // If there is a resolver node for the "used" package,
+ // then this means that the module imports the package
+ // and we need to recursively add the constraints of
+ // the potential exporting module.
+ if (node != null)
+ {
+ usesMap = calculateUsesDependencies(
+ resolverMap,
+ node.m_candidates[node.m_idx],
+ Util.getExportPackage(node.m_candidates[node.m_idx], node.m_import.getName()),
+ usesMap);
+ }
+ // If there was no resolver node for the "used" package,
+ // then this means that the module exports the package
+ // and we need to recursively add the constraints of this
+ // other exported package of this module.
+ else if (Util.getExportPackage(module, uses[usesIdx]) != null)
+ {
+ usesMap = calculateUsesDependencies(
+ resolverMap,
+ module,
+ Util.getExportPackage(module, uses[usesIdx]),
+ usesMap);
+ }
+ }
+ }
+
+ return usesMap;
+ }
+
+ private void incrementCandidateConfiguration(List resolverList)
+ throws ResolveException
+ {
+ for (int i = 0; i < resolverList.size(); i++)
+ {
+ List nodeList = (List) resolverList.get(i);
+ for (int j = 0; j < nodeList.size(); j++)
+ {
+ ResolverNode node = (ResolverNode) nodeList.get(j);
+ // See if we can increment the node, without overflowing
+ // the candidate array bounds.
+ if ((node.m_idx + 1) < node.m_candidates.length)
+ {
+ node.m_idx++;
+ return;
+ }
+ // If the index will overflow the candidate array bounds,
+ // then set the index back to zero and try to increment
+ // the next candidate.
+ else
+ {
+ node.m_idx = 0;
+ }
+ }
+ }
+ throw new ResolveException(
+ "Unable to resolve due to constraint violation.", null, null);
+ }
+
+ private Map createWires(Map resolverMap, IModule rootModule)
+ {
+ Map resolvedModuleWireMap =
+ populateWireMap(resolverMap, rootModule, new HashMap());
+ Iterator iter = resolvedModuleWireMap.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ IModule module = (IModule) entry.getKey();
+ R4Wire[] wires = (R4Wire[]) entry.getValue();
+
+ // Set the module's resolved and wiring attribute.
+ setResolved(module, true);
+ // Only add wires attribute if some exist; export
+ // only modules may not have wires.
+ if (wires.length > 0)
+ {
+ setWires(module, wires);
+ }
+
+ // Remove the wire's exporting module from the "available"
+ // package map and put it into the "in use" package map;
+ // these steps may be a no-op.
+ for (int wireIdx = 0;
+ (wires != null) && (wireIdx < wires.length);
+ wireIdx++)
+ {
+m_logger.log(Logger.LOG_DEBUG, "WIRE: [" + module + "] " + wires[wireIdx]);
+ // First remove the wire module from "available" package map.
+ IModule[] modules = (IModule[]) m_availPkgMap.get(wires[wireIdx].getExport().getName());
+ modules = removeModuleFromArray(modules, wires[wireIdx].getExportingModule());
+ m_availPkgMap.put(wires[wireIdx].getExport().getName(), modules);
+
+ // Also remove any exported packages from the "available"
+ // package map that are from the module associated with
+ // the current wires where the exported packages were not
+ // actually exported; an export may not be exported if
+ // the module also imports the same package and was wired
+ // to a different module. If the exported package is not
+ // actually exported, then we just want to remove it
+ // completely, since it cannot be used.
+ if (wires[wireIdx].getExportingModule() != module)
+ {
+ modules = (IModule[]) m_availPkgMap.get(wires[wireIdx].getExport().getName());
+ modules = removeModuleFromArray(modules, module);
+ m_availPkgMap.put(wires[wireIdx].getExport().getName(), modules);
+ }
+
+ // Add the module of the wire to the "in use" package map.
+ modules = (IModule[]) m_inUsePkgMap.get(wires[wireIdx].getExport().getName());
+ modules = addModuleToArray(modules, wires[wireIdx].getExportingModule());
+ m_inUsePkgMap.put(wires[wireIdx].getExport().getName(), modules);
+ }
+ }
+ return resolvedModuleWireMap;
+ }
+
+ private Map populateWireMap(Map resolverMap, IModule module, Map wireMap)
+ {
+ // If the module is already resolved or it is part of
+ // a cycle, then just return the wire map.
+ if (isResolved(module) || (wireMap.get(module) != null))
+ {
+ return wireMap;
+ }
+
+ List nodeList = (List) resolverMap.get(module);
+ R4Wire[] wires = new R4Wire[nodeList.size()];
+
+ // Put the module in the wireMap with an empty wire array;
+ // we do this early so we can use it to detect cycles.
+ wireMap.put(module, wires);
+
+ // Loop through each resolver node and create a wire
+ // for the selected candidate for the associated import.
+ for (int nodeIdx = 0; nodeIdx < nodeList.size(); nodeIdx++)
+ {
+ // Get the import's associated resolver node.
+ ResolverNode node = (ResolverNode) nodeList.get(nodeIdx);
+
+ // Add the candidate to the list of wires.
+ R4Export export =
+ Util.getExportPackage(node.m_candidates[node.m_idx], node.m_import.getName());
+ wires[nodeIdx] = new R4Wire(module, node.m_candidates[node.m_idx], export);
+
+ // Create the wires for the selected candidate module.
+ wireMap = populateWireMap(resolverMap, node.m_candidates[node.m_idx], wireMap);
+ }
+
+ return wireMap;
+ }
+
+ //
+ // Event handling methods for validation events.
+ //
+
+ /**
+ * Adds a resolver listener to the search policy. Resolver
+ * listeners are notified when a module is resolve and/or unresolved
+ * by the search policy.
+ * @param l the resolver listener to add.
+ **/
+ public void addResolverListener(ResolveListener l)
+ {
+ // Verify listener.
+ if (l == null)
+ {
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ // Use the m_noListeners object as a lock.
+ synchronized (m_emptyListeners)
+ {
+ // If we have no listeners, then just add the new listener.
+ if (m_listeners == m_emptyListeners)
+ {
+ m_listeners = new ResolveListener[] { l };
+ }
+ // Otherwise, we need to do some array copying.
+ // Notice, the old array is always valid, so if
+ // the dispatch thread is in the middle of a dispatch,
+ // then it has a reference to the old listener array
+ // and is not affected by the new value.
+ else
+ {
+ ResolveListener[] newList = new ResolveListener[m_listeners.length + 1];
+ System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
+ newList[m_listeners.length] = l;
+ m_listeners = newList;
+ }
+ }
+ }
+
+ /**
+ * Removes a resolver listener to this search policy.
+ * @param l the resolver listener to remove.
+ **/
+ public void removeResolverListener(ResolveListener l)
+ {
+ // Verify listener.
+ if (l == null)
+ {
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ // Use the m_emptyListeners object as a lock.
+ synchronized (m_emptyListeners)
+ {
+ // Try to find the instance in our list.
+ int idx = -1;
+ for (int i = 0; i < m_listeners.length; i++)
+ {
+ if (m_listeners[i].equals(l))
+ {
+ idx = i;
+ break;
+ }
+ }
+
+ // If we have the instance, then remove it.
+ if (idx >= 0)
+ {
+ // If this is the last listener, then point to empty list.
+ if (m_listeners.length == 1)
+ {
+ m_listeners = m_emptyListeners;
+ }
+ // Otherwise, we need to do some array copying.
+ // Notice, the old array is always valid, so if
+ // the dispatch thread is in the middle of a dispatch,
+ // then it has a reference to the old listener array
+ // and is not affected by the new value.
+ else
+ {
+ ResolveListener[] newList = new ResolveListener[m_listeners.length - 1];
+ System.arraycopy(m_listeners, 0, newList, 0, idx);
+ if (idx < newList.length)
+ {
+ System.arraycopy(m_listeners, idx + 1, newList, idx,
+ newList.length - idx);
+ }
+ m_listeners = newList;
+ }
+ }
+ }
+ }
+
+ /**
+ * Fires a validation event for the specified module.
+ * @param module the module that was resolved.
+ **/
+ private void fireModuleResolved(IModule module)
+ {
+ // Event holder.
+ ModuleEvent event = null;
+
+ // Get a copy of the listener array, which is guaranteed
+ // to not be null.
+ ResolveListener[] listeners = m_listeners;
+
+ // Loop through listeners and fire events.
+ for (int i = 0; i < listeners.length; i++)
+ {
+ // Lazily create event.
+ if (event == null)
+ {
+ event = new ModuleEvent(m_factory, module);
+ }
+ listeners[i].moduleResolved(event);
+ }
+ }
+
+ /**
+ * Fires an unresolved event for the specified module.
+ * @param module the module that was unresolved.
+ **/
+ private void fireModuleUnresolved(IModule module)
+ {
+// TODO: Call this method where appropriate.
+ // Event holder.
+ ModuleEvent event = null;
+
+ // Get a copy of the listener array, which is guaranteed
+ // to not be null.
+ ResolveListener[] listeners = m_listeners;
+
+ // Loop through listeners and fire events.
+ for (int i = 0; i < listeners.length; i++)
+ {
+ // Lazily create event.
+ if (event == null)
+ {
+ event = new ModuleEvent(m_factory, module);
+ }
+ listeners[i].moduleUnresolved(event);
+ }
+ }
+
+ //
+ // ModuleListener callback methods.
+ //
+
+ public void moduleAdded(ModuleEvent event)
+ {
+ }
+
+ public void moduleRemoved(ModuleEvent event)
+ {
+ // When a module is removed from the system, we need remove
+ // its exports from the "in use" and "available" package maps
+ // as well as remove the module from the module data map.
+
+ // Synchronize on the module manager, since we don't want any
+ // bundles to be installed or removed.
+ synchronized (m_factory)
+ {
+ // Remove exports from package maps.
+ R4Export[] exports = getExports(event.getModule());
+ for (int i = 0; (exports != null) && (i < exports.length); i++)
+ {
+ // Remove from "available" package map.
+ IModule[] modules = (IModule[]) m_availPkgMap.get(exports[i].getName());
+ if (modules != null)
+ {
+ modules = removeModuleFromArray(modules, event.getModule());
+ m_availPkgMap.put(exports[i].getName(), modules);
+ }
+ // Remove from "in use" package map.
+ modules = (IModule[]) m_inUsePkgMap.get(exports[i].getName());
+ if (modules != null)
+ {
+ modules = removeModuleFromArray(modules, event.getModule());
+ m_inUsePkgMap.put(exports[i].getName(), modules);
+ }
+ }
+
+ // Finally, remove module data.
+ m_moduleDataMap.remove(event.getModule());
+ }
+ }
+
+ //
+ // Simple utility methods.
+ //
+
+ private static IModule[] addModuleToArray(IModule[] modules, IModule m)
+ {
+ // Verify that the module is not already in the array.
+ for (int i = 0; (modules != null) && (i < modules.length); i++)
+ {
+ if (modules[i] == m)
+ {
+ return modules;
+ }
+ }
+
+ if (modules != null)
+ {
+ IModule[] newModules = new IModule[modules.length + 1];
+ System.arraycopy(modules, 0, newModules, 0, modules.length);
+ newModules[modules.length] = m;
+ modules = newModules;
+ }
+ else
+ {
+ modules = new IModule[] { m };
+ }
+
+ return modules;
+ }
+
+ private static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
+ {
+ if (modules == null)
+ {
+ return m_emptyModules;
+ }
+
+ int idx = -1;
+ for (int i = 0; i < modules.length; i++)
+ {
+ if (modules[i] == m)
+ {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx >= 0)
+ {
+ // If this is the module, then point to empty list.
+ if ((modules.length - 1) == 0)
+ {
+ modules = m_emptyModules;
+ }
+ // Otherwise, we need to do some array copying.
+ else
+ {
+ IModule[] newModules= new IModule[modules.length - 1];
+ System.arraycopy(modules, 0, newModules, 0, idx);
+ if (idx < newModules.length)
+ {
+ System.arraycopy(
+ modules, idx + 1, newModules, idx, newModules.length - idx);
+ }
+ modules = newModules;
+ }
+ }
+ return modules;
+ }
+
+ private static IModule[] shrinkModuleArray(IModule[] modules)
+ {
+ if (modules == null)
+ {
+ return m_emptyModules;
+ }
+
+ int count = 0;
+ for (int i = 0; i < modules.length; i++)
+ {
+ if (modules[i] == null)
+ {
+ count++;
+ }
+ }
+
+ if (count > 0)
+ {
+ IModule[] newModules = new IModule[modules.length - count];
+ count = 0;
+ for (int i = 0; i < modules.length; i++)
+ {
+ if (modules[i] != null)
+ {
+ newModules[count++] = modules[i];
+ }
+ }
+ modules = newModules;
+ }
+
+ return modules;
+ }
+
+ //
+ // Simple utility classes.
+ //
+
+ private static class ModuleData
+ {
+ public IModule m_module = null;
+ public R4Export[] m_exports = null;
+ public R4Import[] m_imports = null;
+ public R4Import[] m_dynamicImports = null;
+ public R4Library[] m_libraries = null;
+ public R4Wire[] m_wires = null;
+ public boolean m_resolved = false;
+ public ModuleData(IModule module)
+ {
+ m_module = module;
+ }
+ }
+
+ private class ResolverNode
+ {
+ public IModule m_module = null;
+ public R4Import m_import = null;
+ public IModule[] m_candidates = null;
+ public int m_idx = 0;
+ public boolean m_visited = false;
+ public ResolverNode(IModule module, R4Import imp, IModule[] candidates)
+ {
+ m_module = module;
+ m_import = imp;
+ m_candidates = candidates;
+ if (isResolved(m_module))
+ {
+ m_visited = true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Version.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Version.java
deleted file mode 100644
index c57975e..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Version.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.searchpolicy;
-
-import java.util.StringTokenizer;
-
-public class R4Version implements Comparable
-{
- private int m_major = 0;
- private int m_minor = 0;
- private int m_micro = 0;
- private String m_qualifier = "";
- private boolean m_isInclusive = true;
-
- private static final String SEPARATOR = ".";
-
- public R4Version(String versionString)
- {
- this(versionString, true);
- }
-
- public R4Version(String versionString, boolean isInclusive)
- {
- if (versionString == null)
- {
- versionString = "0.0.0";
- }
- Object[] objs = parseVersion(versionString);
- m_major = ((Integer) objs[0]).intValue();
- m_minor = ((Integer) objs[1]).intValue();
- m_micro = ((Integer) objs[2]).intValue();
- m_qualifier = (String) objs[3];
- m_isInclusive = isInclusive;
- }
-
- private static Object[] parseVersion(String versionString)
- {
- String s = versionString.trim();
- Object[] objs = new Object[4];
- objs[0] = objs[1] = objs[2] = new Integer(0);
- objs[3] = "";
- StringTokenizer tok = new StringTokenizer(s, SEPARATOR);
- try
- {
- objs[0] = Integer.valueOf(tok.nextToken());
- if (tok.hasMoreTokens())
- {
- objs[1] = Integer.valueOf(tok.nextToken());
- if (tok.hasMoreTokens())
- {
- objs[2] = Integer.valueOf(tok.nextToken());
- if (tok.hasMoreTokens())
- {
- objs[3] = tok.nextToken();
- }
- }
- }
- }
- catch (NumberFormatException ex)
- {
- throw new IllegalArgumentException("Invalid version: " + versionString);
- }
-
- if ((((Integer) objs[0]).intValue() < 0) ||
- (((Integer) objs[0]).intValue() < 0) ||
- (((Integer) objs[0]).intValue() < 0))
- {
- throw new IllegalArgumentException("Invalid version: " + versionString);
- }
-
- return objs;
- }
-
- public boolean equals(Object object)
- {
- if (!(object instanceof R4Version))
- {
- return false;
- }
- R4Version v = (R4Version) object;
- return
- (v.getMajorComponent() == m_major) &&
- (v.getMinorComponent() == m_minor) &&
- (v.getMicroComponent() == m_micro) &&
- (v.getQualifierComponent().equals(m_qualifier));
- }
-
- public int getMajorComponent()
- {
- return m_major;
- }
-
- public int getMinorComponent()
- {
- return m_minor;
- }
-
- public int getMicroComponent()
- {
- return m_micro;
- }
-
- public String getQualifierComponent()
- {
- return m_qualifier;
- }
-
- public boolean isInclusive()
- {
- return m_isInclusive;
- }
-
- public int compareTo(Object o)
- {
- if (!(o instanceof R4Version))
- throw new ClassCastException();
-
- if (equals(o))
- return 0;
-
- if (isGreaterThan((R4Version) o))
- return 1;
-
- return -1;
- }
-
- public boolean isGreaterThan(R4Version v)
- {
- if (v == null)
- {
- return false;
- }
-
- if (m_major > v.getMajorComponent())
- {
- return true;
- }
- if (m_major < v.getMajorComponent())
- {
- return false;
- }
- if (m_minor > v.getMinorComponent())
- {
- return true;
- }
- if (m_minor < v.getMinorComponent())
- {
- return false;
- }
- if (m_micro > v.getMicroComponent())
- {
- return true;
- }
- if (m_micro < v.getMicroComponent())
- {
- return false;
- }
- if (m_qualifier.compareTo(v.getQualifierComponent()) > 0)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- public String toString()
- {
- if (m_qualifier.length() == 0)
- {
- return m_major + "." + m_minor + "." + m_micro;
- }
- return m_major + "." + m_minor + "." + m_micro + "." + m_qualifier;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java
index e249fcc..5f5e361 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,21 +16,100 @@
*/
package org.apache.felix.framework.searchpolicy;
-import org.apache.felix.moduleloader.Module;
+import java.net.URL;
+
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.moduleloader.*;
public class R4Wire
{
- public R4Package m_pkg = null;
- public Module m_module = null;
-
- public R4Wire(R4Package pkg, Module module)
+ private IModule m_importer = null;
+ private IModule m_exporter = null;
+ private R4Export m_export= null;
+
+ public R4Wire(IModule importer, IModule exporter, R4Export export)
{
- m_pkg = pkg;
- m_module = module;
+ m_importer = importer;
+ m_exporter = exporter;
+ m_export = export;
}
-
+
+ public IModule getImportingModule()
+ {
+ return m_importer;
+ }
+
+ public IModule getExportingModule()
+ {
+ return m_exporter;
+ }
+
+ public R4Export getExport()
+ {
+ return m_export;
+ }
+
+ public Class getClass(String name) throws ClassNotFoundException
+ {
+ Class clazz = null;
+
+ // Get the package of the target class.
+ String pkgName = Util.getClassPackage(name);
+
+ // Only check when the package of the target class is
+ // the same as the package for the wire.
+ if (m_export.getName().equals(pkgName))
+ {
+ // Before delegating to the exporting module to satisfy
+ // the class load, we must check the include/exclude filters
+ // from the target package to make sure that the class is
+ // actually visible. However, if the exporting module is the
+ // same as the requesting module, then filtering is not
+ // performed since a module has complete access to itself.
+ if ((m_exporter == m_importer) || m_export.isIncluded(name))
+ {
+ clazz = m_exporter.getContentLoader().getClass(name);
+ }
+
+ // If no class was found, then we must throw an exception
+ // since the exporter for this package did not contain the
+ // requested class.
+ if (clazz == null)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ return clazz;
+ }
+
+ public URL getResource(String name) throws ResourceNotFoundException
+ {
+ URL url = null;
+
+ // Get the package of the target class.
+ String pkgName = Util.getResourcePackage(name);
+
+ // Only check when the package of the target resource is
+ // the same as the package for the wire.
+ if (m_export.getName().equals(pkgName))
+ {
+ url = m_exporter.getContentLoader().getResource(name);
+
+ // If no resource was found, then we must throw an exception
+ // since the exporter for this package did not contain the
+ // requested class.
+ if (url == null)
+ {
+ throw new ResourceNotFoundException(name);
+ }
+ }
+
+ return url;
+ }
+
public String toString()
{
- return m_pkg.getId() + " -> " + m_module;
+ return m_importer + " -> " + m_export.getName() + " -> " + m_exporter;
}
}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ResolveException.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java
similarity index 84%
rename from org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ResolveException.java
rename to org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java
index abc342c..b1632da 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ResolveException.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveException.java
@@ -14,10 +14,9 @@
* limitations under the License.
*
*/
-package org.apache.felix.moduleloader.search;
+package org.apache.felix.framework.searchpolicy;
-import org.apache.felix.framework.searchpolicy.R4Package;
-import org.apache.felix.moduleloader.Module;
+import org.apache.felix.moduleloader.IModule;
/**
* <p>
@@ -30,14 +29,14 @@
**/
public class ResolveException extends Exception
{
- private Module m_module = null;
+ private IModule m_module = null;
private R4Package m_pkg = null;
/**
* Constructs an exception with the specified message, module,
* import identifier, import version number, and propagation flag.
**/
- public ResolveException(String msg, Module module, R4Package pkg)
+ public ResolveException(String msg, IModule module, R4Package pkg)
{
super(msg);
m_module = module;
@@ -48,7 +47,7 @@
* Returns the module that was being resolved.
* @return the module that was being resolved.
**/
- public Module getModule()
+ public IModule getModule()
{
return m_module;
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ResolveListener.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java
similarity index 92%
rename from org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ResolveListener.java
rename to org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java
index a502021..2ed2a62 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ResolveListener.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolveListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
-package org.apache.felix.moduleloader.search;
+package org.apache.felix.framework.searchpolicy;
import java.util.EventListener;
@@ -26,7 +26,7 @@
* events that are generated by the <tt>R4SearchPolicy</tt>. Events
* are fired when a module is resolved and when it is unresolved.
* </p>
- * @see org.apache.felix.framework.searchpolicy.R4SearchPolicy
+ * @see org.apache.felix.framework.searchpolicy.R4SearchPolicyCore
**/
public interface ResolveListener extends EventListener
{
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java
new file mode 100644
index 0000000..19cf1cf
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import java.net.*;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.SecureAction;
+import org.apache.felix.moduleloader.IModule;
+import org.apache.felix.moduleloader.IURLPolicy;
+
+public class URLPolicyImpl implements IURLPolicy
+{
+ private Logger m_logger = null;
+ private URLStreamHandler m_streamHandler = null;
+ private IModule m_module = null;
+ private static SecureAction m_secureAction = new SecureAction();
+
+// TODO: FIX - IT SUCKS HAVING A URL POLICY OBJECT PER MODULE!
+ public URLPolicyImpl(Logger logger, URLStreamHandler streamHandler, IModule module)
+ {
+ m_logger = logger;
+ m_streamHandler = streamHandler;
+ m_module = module;
+ }
+
+ public URL createURL(String path)
+ {
+ // Add a slash if there is one already, otherwise
+ // the is no slash separating the host from the file
+ // in the resulting URL.
+ if (!path.startsWith("/"))
+ {
+ path = "/" + path;
+ }
+
+ try
+ {
+ return m_secureAction.createURL(
+ FelixConstants.BUNDLE_URL_PROTOCOL,
+ m_module.getId(), -1, path, m_streamHandler);
+ }
+ catch (MalformedURLException ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to create resource URL.",
+ ex);
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java
new file mode 100644
index 0000000..c77a63e
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.searchpolicy;
+
+import org.osgi.framework.Version;
+
+public class VersionRange
+{
+ private Version m_low = null;
+ private boolean m_isLowInclusive = false;
+ private Version m_high = null;
+ private boolean m_isHighInclusive = false;
+
+ public VersionRange(Version low, boolean isLowInclusive,
+ Version high, boolean isHighInclusive)
+ {
+ m_low = low;
+ m_isLowInclusive = isLowInclusive;
+ m_high = high;
+ m_isHighInclusive = isHighInclusive;
+ }
+
+ public Version getLow()
+ {
+ return m_low;
+ }
+
+ public boolean isLowInclusive()
+ {
+ return m_isLowInclusive;
+ }
+
+ public Version getHigh()
+ {
+ return m_high;
+ }
+
+ public boolean isHighInclusive()
+ {
+ return m_isHighInclusive;
+ }
+
+ public boolean isInRange(Version version)
+ {
+ // We might not have an upper end to the range.
+ if (m_high == null)
+ {
+ return (version.compareTo(m_low) >= 0);
+ }
+ else if (isLowInclusive() && isHighInclusive())
+ {
+ return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) <= 0);
+ }
+ else if (isHighInclusive())
+ {
+ return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) <= 0);
+ }
+ else if (isLowInclusive())
+ {
+ return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) < 0);
+ }
+ return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) < 0);
+ }
+
+ public static VersionRange parse(String range)
+ {
+ // Check if the version is an interval.
+ if (range.indexOf(',') >= 0)
+ {
+ String s = range.substring(1, range.length() - 1);
+ String vlo = s.substring(0, s.indexOf(','));
+ String vhi = s.substring(s.indexOf(',') + 1, s.length());
+ return new VersionRange (
+ new Version(vlo), (range.charAt(0) == '['),
+ new Version(vhi), (range.charAt(range.length() - 1) == ']'));
+ }
+ else
+ {
+ return new VersionRange(new Version(range), true, null, false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java
index 73d8086..b27278d 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java
@@ -18,7 +18,7 @@
import java.util.*;
-import org.apache.felix.framework.LogWrapper;
+import org.apache.felix.framework.Logger;
/**
* This class implements an event dispatching queue to simplify delivering
@@ -66,13 +66,13 @@
// Cached dispatch requests to avoid memory allocation.
private static final ArrayList m_requestCache = new ArrayList();
// The logger for dispatch queue.
- private static LogWrapper m_logger = null;
+ private static Logger m_logger = null;
/**
* Constructs a dispatch queue and starts a dispather thread if
* necessary.
**/
- public DispatchQueue(LogWrapper logger)
+ public DispatchQueue(Logger logger)
{
synchronized (m_threadLock)
{
@@ -127,7 +127,7 @@
}
}
- public static LogWrapper getLogger()
+ public static Logger getLogger()
{
return m_logger;
}
@@ -360,7 +360,7 @@
try {
m_requestList.wait();
} catch (InterruptedException ex) {
- m_logger.log(LogWrapper.LOG_ERROR, "DispatchQueue: Thread interrupted.", ex);
+ m_logger.log(Logger.LOG_ERROR, "DispatchQueue: Thread interrupted.", ex);
}
}
@@ -396,7 +396,7 @@
dr.m_dispatcher.dispatch(
(EventListener) dr.m_listeners[i + 1], dr.m_eventObj);
} catch (Throwable th) {
- m_logger.log(LogWrapper.LOG_ERROR, "DispatchQueue: Error during dispatch.", th);
+ m_logger.log(Logger.LOG_ERROR, "DispatchQueue: Error during dispatch.", th);
}
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java
index 4a008b3..354c05b 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java
@@ -19,7 +19,7 @@
import java.util.EventListener;
import java.util.EventObject;
-import org.apache.felix.framework.LogWrapper;
+import org.apache.felix.framework.Logger;
import org.osgi.framework.*;
/**
@@ -36,7 +36,7 @@
**/
public class FelixDispatchQueue extends DispatchQueue
{
- public FelixDispatchQueue(LogWrapper logger)
+ public FelixDispatchQueue(Logger logger)
{
super(logger);
}
@@ -77,7 +77,7 @@
(EventListener) lw, eventObj);
} catch (Throwable th) {
getLogger().log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"FelixDispatchQueue: Error during dispatch.", th);
}
}
@@ -100,7 +100,7 @@
(EventListener) lw, eventObj);
} catch (Throwable th) {
getLogger().log(
- LogWrapper.LOG_ERROR,
+ Logger.LOG_ERROR,
"FelixDispatchQueue: Error during dispatch.", th);
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ObjectInputStreamX.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ObjectInputStreamX.java
index b7f79a8..e30b47c 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ObjectInputStreamX.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ObjectInputStreamX.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
import java.io.*;
+import org.apache.felix.moduleloader.IContentLoader;
+
/**
* The ObjectInputStreamX class is a simple extension to the ObjectInputStream
* class. The purpose of ObjectInputStreamX is to allow objects to be deserialized
@@ -25,7 +27,7 @@
*/
public class ObjectInputStreamX extends ObjectInputStream
{
- private ClassLoader m_loader = null;
+ private IContentLoader m_contentLoader = null;
/**
* Construct an ObjectInputStreamX for the specified InputStream and the specified
@@ -33,11 +35,11 @@
* @param in the input stream to read.
* @param loader the class loader used to resolve classes.
*/
- public ObjectInputStreamX(InputStream in, ClassLoader loader)
+ public ObjectInputStreamX(InputStream in, IContentLoader contentLoader)
throws IOException, StreamCorruptedException
{
super(in);
- this.m_loader = loader;
+ m_contentLoader = contentLoader;
}
/**
@@ -47,7 +49,6 @@
protected Class resolveClass(ObjectStreamClass v)
throws IOException, ClassNotFoundException
{
- Class clazz = m_loader.loadClass(v.getName());
- return clazz;
+ return m_contentLoader.getClass(v.getName());
}
}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/SecureAction.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
index 759305d..545425a 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
@@ -16,6 +16,7 @@
*/
package org.apache.felix.framework.util;
+import java.net.*;
import java.security.*;
/**
@@ -33,20 +34,21 @@
public class SecureAction
{
private AccessControlContext m_acc = null;
+ private Actions m_actions = new Actions();
public SecureAction()
{
m_acc = AccessController.getContext();
}
- public String getProperty(String name, String def)
+ public synchronized String getProperty(String name, String def)
{
if (System.getSecurityManager() != null)
{
try
{
- return (String) AccessController.doPrivileged(
- new Actions(Actions.GET_PROPERTY_ACTION, name, def), m_acc);
+ m_actions.set(Actions.GET_PROPERTY_ACTION, name, def);
+ return (String) AccessController.doPrivileged(m_actions, m_acc);
}
catch (PrivilegedActionException ex)
{
@@ -59,14 +61,14 @@
}
}
- public Class forName(String name) throws ClassNotFoundException
+ public synchronized Class forName(String name) throws ClassNotFoundException
{
if (System.getSecurityManager() != null)
{
try
{
- return (Class) AccessController.doPrivileged(
- new Actions(Actions.FOR_NAME_ACTION, name), m_acc);
+ m_actions.set(Actions.FOR_NAME_ACTION, name);
+ return (Class) AccessController.doPrivileged(m_actions, m_acc);
}
catch (PrivilegedActionException ex)
{
@@ -83,26 +85,87 @@
}
}
+ public synchronized URL createURL(String protocol, String host,
+ int port, String path, URLStreamHandler handler)
+ throws MalformedURLException
+ {
+ if (System.getSecurityManager() != null)
+ {
+ try
+ {
+ m_actions.set(
+ Actions.CREATE_URL_ACTION, protocol, host, port, path, handler);
+ return (URL) AccessController.doPrivileged(m_actions, m_acc);
+ }
+ catch (PrivilegedActionException ex)
+ {
+ if (ex.getException() instanceof MalformedURLException)
+ {
+ throw (MalformedURLException) ex.getException();
+ }
+ throw (RuntimeException) ex.getException();
+ }
+ }
+ else
+ {
+ return new URL(protocol, host, port, path, handler);
+ }
+ }
+
private static class Actions implements PrivilegedExceptionAction
{
public static final int GET_PROPERTY_ACTION = 0;
public static final int FOR_NAME_ACTION = 1;
+ public static final int CREATE_URL_ACTION = 2;
private int m_action = -1;
private Object m_arg1 = null;
private Object m_arg2 = null;
- public Actions(int action, Object arg1)
+ private String m_protocol = null;
+ private String m_host = null;
+ private int m_port = -1;
+ private String m_path = null;
+ private URLStreamHandler m_handler = null;
+
+ public void set(int action, Object arg1)
{
m_action = action;
m_arg1 = arg1;
+
+ m_arg2 = null;
+ m_protocol = null;
+ m_host = null;
+ m_port = -1;
+ m_path = null;
+ m_handler = null;
}
- public Actions(int action, Object arg1, Object arg2)
+ public void set(int action, Object arg1, Object arg2)
{
m_action = action;
m_arg1 = arg1;
m_arg2 = arg2;
+
+ m_protocol = null;
+ m_host = null;
+ m_port = -1;
+ m_path = null;
+ m_handler = null;
+ }
+
+ public void set(int action, String protocol, String host,
+ int port, String path, URLStreamHandler handler)
+ {
+ m_action = action;
+ m_protocol = protocol;
+ m_host = host;
+ m_port = port;
+ m_path = path;
+ m_handler = handler;
+
+ m_arg1 = null;
+ m_arg2 = null;
}
public Object run() throws Exception
@@ -111,10 +174,14 @@
{
return System.getProperty((String) m_arg1, (String) m_arg2);
}
- else if (m_action ==FOR_NAME_ACTION)
+ else if (m_action == FOR_NAME_ACTION)
{
return Class.forName((String) m_arg1);
}
+ else if (m_action == CREATE_URL_ACTION)
+ {
+ return new URL(m_protocol, m_host, m_port, m_path, m_handler);
+ }
return null;
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Util.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Util.java
index 534b776..bf3e922 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Util.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Util.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +20,137 @@
import java.util.ArrayList;
import java.util.List;
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.searchpolicy.*;
+import org.apache.felix.moduleloader.IModule;
+
public class Util
{
/**
+ * Converts a module identifier to a bundle identifier. Module IDs
+ * are typically <tt><bundle-id>.<revision></tt>; this
+ * method returns only the portion corresponding to the bundle ID.
+ **/
+ public static long getBundleIdFromModuleId(String id)
+ {
+ try
+ {
+ String bundleId = (id.indexOf('.') >= 0)
+ ? id.substring(0, id.indexOf('.')) : id;
+ return Long.parseLong(bundleId);
+ }
+ catch (NumberFormatException ex)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * Converts a module identifier to a bundle identifier. Module IDs
+ * are typically <tt><bundle-id>.<revision></tt>; this
+ * method returns only the portion corresponding to the revision.
+ **/
+ public static int getModuleRevisionFromModuleId(String id)
+ {
+ try
+ {
+ String rev = (id.indexOf('.') >= 0)
+ ? id.substring(id.indexOf('.') + 1) : id;
+ return Integer.parseInt(rev);
+ }
+ catch (NumberFormatException ex)
+ {
+ return -1;
+ }
+ }
+
+ public static String getClassName(String className)
+ {
+ if (className == null)
+ {
+ className = "";
+ }
+ return (className.lastIndexOf('.') < 0)
+ ? "" : className.substring(className.lastIndexOf('.') + 1);
+ }
+
+ public static String getClassPackage(String className)
+ {
+ if (className == null)
+ {
+ className = "";
+ }
+ return (className.lastIndexOf('.') < 0)
+ ? "" : className.substring(0, className.lastIndexOf('.'));
+ }
+
+ public static String getResourcePackage(String resource)
+ {
+ if (resource == null)
+ {
+ resource = "";
+ }
+ // NOTE: The package of a resource is tricky to determine since
+ // resources do not follow the same naming conventions as classes.
+ // This code is pessimistic and assumes that the package of a
+ // resource is everything up to the last '/' character. By making
+ // this choice, it will not be possible to load resources from
+ // imports using relative resource names. For example, if a
+ // bundle exports "foo" and an importer of "foo" tries to load
+ // "/foo/bar/myresource.txt", this will not be found in the exporter
+ // because the following algorithm assumes the package name is
+ // "foo.bar", not just "foo". This only affects imported resources,
+ // local resources will work as expected.
+ String pkgName = (resource.startsWith("/")) ? resource.substring(1) : resource;
+ pkgName = (pkgName.lastIndexOf('/') < 0)
+ ? "" : pkgName.substring(0, pkgName.lastIndexOf('/'));
+ pkgName = pkgName.replace('/', '.');
+ return pkgName;
+ }
+
+ public static R4Export getExportPackage(IModule m, String name)
+ {
+ R4Export[] pkgs =
+ ((IR4SearchPolicy) m.getContentLoader().getSearchPolicy()).getExports();
+ for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
+ {
+ if (pkgs[i].getName().equals(name))
+ {
+ return pkgs[i];
+ }
+ }
+ return null;
+ }
+
+ public static R4Import getImportPackage(IModule m, String name)
+ {
+ R4Import[] pkgs =
+ ((IR4SearchPolicy) m.getContentLoader().getSearchPolicy()).getImports();
+ for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
+ {
+ if (pkgs[i].getName().equals(name))
+ {
+ return pkgs[i];
+ }
+ }
+ return null;
+ }
+
+ public static R4Wire getWire(IModule m, String name)
+ {
+ R4Wire[] wires =
+ ((IR4SearchPolicy) m.getContentLoader().getSearchPolicy()).getWires();
+ for (int i = 0; (wires != null) && (i < wires.length); i++)
+ {
+ if (wires[i].getExport().getName().equals(name))
+ {
+ return wires[i];
+ }
+ }
+ return null;
+ }
+
+ /**
* Parses delimited string and returns an array containing the tokens. This
* parser obeys quotes, so the delimiter character will be ignored if it is
* inside of a quote. This method assumes that the quote character is not
@@ -97,19 +225,19 @@
* @return an array of <tt>LibraryInfo</tt> objects for the
* passed in strings.
**/
- public static LibraryInfo[] parseLibraryStrings(String[] libStrs)
+ public static R4LibraryHeader[] parseLibraryStrings(Logger logger, String[] libStrs)
throws IllegalArgumentException
{
if (libStrs == null)
{
- return null;
+ return new R4LibraryHeader[0];
}
List libList = new ArrayList();
for (int i = 0; i < libStrs.length; i++)
{
- LibraryInfo[] libs = LibraryInfo.parse(libStrs[i]);
+ R4LibraryHeader[] libs = R4LibraryHeader.parse(logger, libStrs[i]);
for (int libIdx = 0;
(libs != null) && (libIdx < libs.length);
libIdx++)
@@ -118,12 +246,7 @@
}
}
- if (libList.size() == 0)
- {
- return null;
- }
-
- return (LibraryInfo[]) libList.toArray(new LibraryInfo[libList.size()]);
+ return (R4LibraryHeader[]) libList.toArray(new R4LibraryHeader[libList.size()]);
}
private static final byte encTab[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/DefaultURLPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/DefaultURLPolicy.java
deleted file mode 100644
index 0aa9d8d..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/DefaultURLPolicy.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.net.URL;
-
-/**
- * <p>
- * This class implements a simple <tt>URLPolicy</tt> that the <tt>ModuleManager</tt>
- * uses if the application does not specify one. This implementation always returns
- * <tt>null</tt> for <tt>CodeSource</tt> <tt>URL</tt>s, which means that security
- * is simply ignored. For resource <tt>URL</tt>s, it returns an <tt>URL</tt> in the
- * form of:
- * </p>
- * <pre>
- * module://<module-id>/<resource-path>
- * </pre>
- * <p>
- * In order to properly handle the "<tt>module:</tt>" protocol, this policy
- * also defines a custom <tt>java.net.URLStreamHandler</tt> that it assigns
- * to each <tt>URL</tt> as it is created. This custom handler is used to
- * return a custom <tt>java.net.URLConnection</tt> that will correctly parse
- * the above <tt>URL</tt> and retrieve the associated resource bytes using
- * methods from <tt>ModuleManager</tt> and <tt>Module</tt>.
- * </p>
- * @see org.apache.felix.moduleloader.ModuleManager
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.URLPolicy
-**/
-public class DefaultURLPolicy implements URLPolicy
-{
- private ModuleURLStreamHandler m_handler = null;
-
- /**
- * <p>
- * This method is a stub and always returns <tt>null</tt>.
- * </p>
- * @param mgr the <tt>ModuleManager</tt> of the module.
- * @param module the module for which the <tt>URL</tt> is to be created.
- * @return <tt>null</tt>.
- **/
- public URL createCodeSourceURL(ModuleManager mgr, Module module)
- {
- return null;
- }
-
- /**
- * <p>
- * This method returns a <tt>URL</tt> that is suitable
- * for accessing the bytes of the specified resource.
- * </p>
- * @param mgr the <tt>ModuleManager</tt> of the module.
- * @param module the module for which the resource is being loaded.
- * @param rsIdx the index of the <tt>ResourceSource</tt> containing the resource.
- * @param name the name of the resource being loaded.
- * @return an <tt>URL</tt> for retrieving the resource.
- **/
- public URL createResourceURL(ModuleManager mgr, Module module, int rsIdx, String name)
- {
- if (m_handler == null)
- {
- m_handler = new ModuleURLStreamHandler(mgr);
- }
-
- // Add a slash if there is one already, otherwise
- // the is no slash separating the host from the file
- // in the resulting URL.
- if (!name.startsWith("/"))
- {
- name = "/" + name;
- }
-
- try
- {
- return new URL("module", module.getId(), -1, "/" + rsIdx + name, m_handler);
- }
- catch (Exception ex)
- {
- System.err.println("DefaultResourceURLPolicy: " + ex);
- return null;
- }
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IContent.java
similarity index 62%
rename from org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
rename to org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IContent.java
index 24595ec..a0e5653 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IContent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,19 +17,15 @@
package org.apache.felix.moduleloader;
import java.io.IOException;
-import java.net.*;
+import java.io.InputStream;
-class ModuleURLStreamHandler extends URLStreamHandler
+public interface IContent
{
- private ModuleManager m_mgr = null;
-
- public ModuleURLStreamHandler(ModuleManager mgr)
- {
- m_mgr = mgr;
- }
-
- protected URLConnection openConnection(URL url) throws IOException
- {
- return new ModuleURLConnection(m_mgr, url);
- }
-}
+ public void open();
+ public void close();
+ public boolean hasEntry(String name);
+ public byte[] getEntry(String name);
+ public InputStream getEntryAsStream(String name)
+ throws IOException;
+ public String[] getEntryPaths(String path);
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IContentLoader.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IContentLoader.java
new file mode 100644
index 0000000..be88eca
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IContentLoader.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.moduleloader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+public interface IContentLoader
+{
+ public void open();
+ public void close();
+
+ public IContent getContent();
+
+ public void setSearchPolicy(ISearchPolicy searchPolicy);
+ public ISearchPolicy getSearchPolicy();
+
+ public void setURLPolicy(IURLPolicy urlPolicy);
+ public IURLPolicy getURLPolicy();
+
+ public Class getClass(String name);
+ public URL getResource(String name);
+
+ public InputStream getResourceAsStream(String name)
+ throws IOException;
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IModule.java
similarity index 60%
copy from org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
copy to org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IModule.java
index 24595ec..84a6db6 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,13 @@
*/
package org.apache.felix.moduleloader;
-import java.io.IOException;
-import java.net.*;
+import java.net.URL;
-class ModuleURLStreamHandler extends URLStreamHandler
+public interface IModule
{
- private ModuleManager m_mgr = null;
+ public String getId();
+ public IContentLoader getContentLoader();
- public ModuleURLStreamHandler(ModuleManager mgr)
- {
- m_mgr = mgr;
- }
-
- protected URLConnection openConnection(URL url) throws IOException
- {
- return new ModuleURLConnection(m_mgr, url);
- }
-}
+ public Class getClass(String name);
+ public URL getResource(String name);
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IModuleFactory.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IModuleFactory.java
new file mode 100644
index 0000000..a920baa
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IModuleFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.moduleloader;
+
+public interface IModuleFactory
+{
+ public IModule[] getModules();
+ public IModule getModule(String id);
+
+ public IModule createModule(String id);
+ public void removeModule(IModule module);
+
+ public void setContentLoader(IModule module, IContentLoader contentLoader);
+
+ public void addModuleListener(ModuleListener l);
+ public void removeModuleListener(ModuleListener l);
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ISearchPolicy.java
similarity index 60%
copy from org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
copy to org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ISearchPolicy.java
index 24595ec..d3dd0d1 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ISearchPolicy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,14 @@
*/
package org.apache.felix.moduleloader;
-import java.io.IOException;
-import java.net.*;
+import java.net.URL;
-class ModuleURLStreamHandler extends URLStreamHandler
+import org.apache.felix.moduleloader.ResourceNotFoundException;
+
+public interface ISearchPolicy
{
- private ModuleManager m_mgr = null;
-
- public ModuleURLStreamHandler(ModuleManager mgr)
- {
- m_mgr = mgr;
- }
-
- protected URLConnection openConnection(URL url) throws IOException
- {
- return new ModuleURLConnection(m_mgr, url);
- }
-}
+ public Object[] definePackage(String name);
+ public Class findClass(String name) throws ClassNotFoundException;
+ public URL findResource(String name) throws ResourceNotFoundException;
+ public String findLibrary(String name);
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IURLPolicy.java
similarity index 60%
copy from org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
copy to org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IURLPolicy.java
index 24595ec..4579b4d 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLStreamHandler.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/IURLPolicy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,9 @@
*/
package org.apache.felix.moduleloader;
-import java.io.IOException;
-import java.net.*;
+import java.net.URL;
-class ModuleURLStreamHandler extends URLStreamHandler
+public interface IURLPolicy
{
- private ModuleManager m_mgr = null;
-
- public ModuleURLStreamHandler(ModuleManager mgr)
- {
- m_mgr = mgr;
- }
-
- protected URLConnection openConnection(URL url) throws IOException
- {
- return new ModuleURLConnection(m_mgr, url);
- }
-}
+ public URL createURL(String path);
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java
new file mode 100644
index 0000000..b7c9aa8
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.moduleloader;
+
+import java.io.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+public class JarContent implements IContent
+{
+ private static final int BUFSIZE = 4096;
+
+ private File m_file = null;
+ private JarFile m_jarFile = null;
+ private boolean m_opened = false;
+
+ public JarContent(File file)
+ {
+ m_file = file;
+ }
+
+ protected void finalize()
+ {
+ if (m_jarFile != null)
+ {
+ try
+ {
+ m_jarFile.close();
+ }
+ catch (IOException ex)
+ {
+ // Not much we can do, so ignore it.
+ }
+ }
+ }
+
+ public void open()
+ {
+ m_opened = true;
+ }
+
+ public synchronized void close()
+ {
+ try
+ {
+ if (m_jarFile != null)
+ {
+ m_jarFile.close();
+ }
+ }
+ catch (Exception ex)
+ {
+ System.err.println("JarContent: " + ex);
+ }
+
+ m_jarFile = null;
+ m_opened = false;
+ }
+
+ public synchronized boolean hasEntry(String name) throws IllegalStateException
+ {
+ if (!m_opened)
+ {
+ throw new IllegalStateException("JarContent is not open");
+ }
+
+ // Open JAR file if not already opened.
+ if (m_jarFile == null)
+ {
+ try
+ {
+ openJarFile();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("JarContent: " + ex);
+ return false;
+ }
+ }
+
+ try
+ {
+ ZipEntry ze = m_jarFile.getEntry(name);
+ return ze != null;
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ finally
+ {
+ }
+ }
+
+ public synchronized byte[] getEntry(String name) throws IllegalStateException
+ {
+ if (!m_opened)
+ {
+ throw new IllegalStateException("JarContent is not open");
+ }
+
+ // Open JAR file if not already opened.
+ if (m_jarFile == null)
+ {
+ try
+ {
+ openJarFile();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("JarResourceSource: " + ex);
+ return null;
+ }
+ }
+
+ // Get the embedded resource.
+ InputStream is = null;
+ ByteArrayOutputStream baos = null;
+
+ try
+ {
+ ZipEntry ze = m_jarFile.getEntry(name);
+ if (ze == null)
+ {
+ return null;
+ }
+ is = m_jarFile.getInputStream(ze);
+ if (is == null)
+ {
+ return null;
+ }
+ baos = new ByteArrayOutputStream(BUFSIZE);
+ byte[] buf = new byte[BUFSIZE];
+ int n = 0;
+ while ((n = is.read(buf, 0, buf.length)) >= 0)
+ {
+ baos.write(buf, 0, n);
+ }
+ return baos.toByteArray();
+
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ finally
+ {
+ try
+ {
+ if (baos != null) baos.close();
+ }
+ catch (Exception ex)
+ {
+ }
+ try
+ {
+ if (is != null) is.close();
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+
+ public synchronized InputStream getEntryAsStream(String name)
+ throws IllegalStateException, IOException
+ {
+ if (!m_opened)
+ {
+ throw new IllegalStateException("JarContent is not open");
+ }
+
+ // Open JAR file if not already opened.
+ if (m_jarFile == null)
+ {
+ try
+ {
+ openJarFile();
+ }
+ catch (IOException ex)
+ {
+ System.err.println("JarResourceSource: " + ex);
+ return null;
+ }
+ }
+
+ // Get the embedded resource.
+ InputStream is = null;
+
+ try
+ {
+ ZipEntry ze = m_jarFile.getEntry(name);
+ if (ze == null)
+ {
+ return null;
+ }
+ is = m_jarFile.getInputStream(ze);
+ if (is == null)
+ {
+ return null;
+ }
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+
+ return is;
+ }
+
+ public String[] getEntryPaths(String path)
+ {
+ return null;
+ }
+
+ private void openJarFile() throws IOException
+ {
+ if (m_jarFile == null)
+ {
+ m_jarFile = new JarFile(m_file);
+ }
+ }
+
+ public String toString()
+ {
+ return "JAR " + m_file.getPath();
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarResourceSource.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarResourceSource.java
deleted file mode 100644
index 0f3fdbf..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarResourceSource.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.io.*;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
-
-/**
- * <p>
- * This class implements a <tt>ResourceSource</tt> for retrieving resources
- * from a JAR file. The approach used by this implementation is to defer
- * opening the JAR file until a request for a resource is made.
- * </p>
- * @see org.apache.felix.moduleloader.ResourceSource
-**/
-public class JarResourceSource implements ResourceSource
-{
- private static final int BUFSIZE = 4096;
-
- private File m_file = null;
- private JarFile m_jarFile = null;
- private boolean m_opened = false;
-
- /**
- * <p>
- * Constructs an instance using the specified file name as the source
- * of the JAR file.
- * </p>
- * @param fileName the name of the JAR file to be used as the source.
- **/
- public JarResourceSource(String fileName)
- {
- m_file = new File(fileName);
- }
-
- /**
- * <p>
- * Constructs an instance using the specified file as the source
- * of the JAR file.
- * </p>
- * @param file the JAR file to be used as the source.
- **/
- public JarResourceSource(File file)
- {
- m_file = file;
- }
-
- /**
- * <p>
- * Closes the JAR file if it has not already been closed.
- * <p>
- **/
- protected void finalize()
- {
- if (m_jarFile != null)
- {
- try {
- m_jarFile.close();
- } catch (IOException ex) {
- // Not much we can do, so ignore it.
- }
- }
- }
-
- /**
- * <p>
- * This method initializes the resource source. Since opening
- * the JAR file is deferred until a request for a resource is
- * actually made, this method really only sets a flag indicating
- * that the resource source has been initialized.
- * <p>
- **/
- public void open()
- {
- m_opened = true;
- }
-
- /**
- * <p>
- * This method deinitializes the resource source by closing
- * the associated JAR file if it is open.
- * <p>
- **/
- public synchronized void close()
- {
- try {
- if (m_jarFile != null)
- {
- m_jarFile.close();
- }
- } catch (Exception ex) {
- System.err.println("JarResourceSource: " + ex);
- }
-
- m_jarFile = null;
- m_opened = false;
- }
-
- // JavaDoc comments are copied from ResourceSource.
- public synchronized boolean hasResource(String name) throws IllegalStateException
- {
- if (!m_opened)
- {
- throw new IllegalStateException("JarResourceSource is not open");
- }
-
- // Open JAR file if not already opened.
- if (m_jarFile == null)
- {
- try {
- openJarFile();
- } catch (IOException ex) {
- System.err.println("JarResourceSource: " + ex);
- return false;
- }
- }
-
- try {
- ZipEntry ze = m_jarFile.getEntry(name);
- return ze != null;
- } catch (Exception ex) {
- return false;
- } finally {
- }
- }
-
- // JavaDoc comments are copied from ResourceSource.
- public synchronized byte[] getBytes(String name) throws IllegalStateException
- {
- if (!m_opened)
- {
- throw new IllegalStateException("JarResourceSource is not open");
- }
-
- // Open JAR file if not already opened.
- if (m_jarFile == null)
- {
- try {
- openJarFile();
- } catch (IOException ex) {
- System.err.println("JarResourceSource: " + ex);
- return null;
- }
- }
-
- // Get the embedded resource.
- InputStream is = null;
- ByteArrayOutputStream baos = null;
-
- try {
- ZipEntry ze = m_jarFile.getEntry(name);
- if (ze == null)
- {
- return null;
- }
- is = m_jarFile.getInputStream(ze);
- if (is == null)
- {
- return null;
- }
- baos = new ByteArrayOutputStream(BUFSIZE);
- byte[] buf = new byte[BUFSIZE];
- int n = 0;
- while ((n = is.read(buf, 0, buf.length)) >= 0)
- {
- baos.write(buf, 0, n);
- }
- return baos.toByteArray();
-
- } catch (Exception ex) {
- return null;
- } finally {
- try {
- if (baos != null) baos.close();
- } catch (Exception ex) {
- }
- try {
- if (is != null) is.close();
- } catch (Exception ex) {
- }
- }
- }
-
- private void openJarFile() throws IOException
- {
- if (m_jarFile == null)
- {
- m_jarFile = new JarFile(m_file);
- }
- }
-
- public String toString()
- {
- return "JAR " + m_file.getPath();
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/LibrarySource.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/LibrarySource.java
deleted file mode 100644
index a0538ae..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/LibrarySource.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-/**
- * <p>
- * This interface represents a source for obtaining native libraries for a
- * given module via the module's class loader. The main goal of a library
- * source is to map a library name to a path in the file system.
- * </p>
- * <p>
- * All library sources are initialized before first usage via a call
- * to the <a href="#open()"><tt>LibrarySource.open()</tt></a> method and
- * are also deinitialized via a call to
- * <a href="#open()"><tt>LibrarySource.close()</tt></a>. Library sources
- * should be implemented such that they can be opened, closed, and then
- * re-opened.
- * </p>
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ModuleClassLoader
-**/
-public interface LibrarySource
-{
- /**
- * <p>
- * This method initializes the library source. It is called when
- * the associated module is added to the <tt>ModuleManager</tt>. It
- * is acceptable for implementations to ignore duplicate calls to this
- * method if the library source is already opened.
- * </p>
- **/
- public void open();
-
- /**
- * <p>
- * This method de-initializes the library source. It is called when
- * the associated module is removed from the <tt>ModuleManager</tt> or
- * when the module is reset by the <tt>ModuleManager</tt>.
- * </p>
- **/
- public void close();
-
- /**
- * <p>
- * Returns a file system path to the specified library.
- * </p>
- * @param name the name of the library that is being requested.
- * @return a file system path to the specified library.
- * @throws java.lang.IllegalStateException if the resource source has not
- * been opened.
- **/
- public String getPath(String name) throws IllegalStateException;
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/Module.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/Module.java
deleted file mode 100644
index 66b64a2..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/Module.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.*;
-
-/**
- * <p>
- * The <tt>Module</tt> class is a grouping mechanism for application classes
- * and resources. Conceptually, most applications are grouped into
- * entities such as JAR files (containing classes and resources) and native
- * libraries. In some cases, these entities are core application classes and
- * resources, while in other cases, these entities are ancillary, such as
- * dynamically loaded plug-ins. Applications place some level of semantics
- * onto these types of entities or <i>modules</i>, but for the <tt>ModuleLoader</tt>,
- * no particular semantics are attached to modules (other than they are a grouping
- * mechanism for classes and resources). This means that the application
- * is free to map itself into modules any way that is appropriate.
- * </p>
- * <p>
- * A module has the following features:
- * </p>
- * <ul>
- * <li>A unique identifier within the scope of its <tt>ModuleManager</tt>.
- * </li>
- * <li>A set of key-value attribute pairs.
- * </li>
- * <li>A set of resource sources from which it is possible to
- * retrieve classes and resources.
- * </li>
- * <li>A set of native library sources from which it is possible
- * to retrieve native libraries.
- * </li>
- * </ul>
- * <p>
- * A module's identifier must be unique within the scope of its
- * <tt>ModuleManager</tt>, but there is no meaning associated with it. The
- * set of attribute-value pairs attached to the module have no meaning to
- * the <tt>ModuleManager</tt>, nor does it consult them at all. The point
- * of these attributes is to attach meta-data for use by
- * <a href="SearchPolicy.html"><tt>SearchPolicy</tt></a> implementations.
- * Attributes are represented as an array of <tt>Object</tt>
- * arrays, i.e., <tt>Object[][]</tt>. Each element in the attribute array is
- * a two-element <tt>Object</tt> array, where <tt>Module.KEY_IDX</tt> is the attribute's
- * key and <tt>Module.VALUE_IDX</tt> is the attribute's value.
- * </p>
- * <p>
- * The actual contents of a module is contained in two sets of sources
- * for its resources and native libraries,
- * <a href="ResourceSource.html"><tt>ResourceSource</tt></a>s
- * and <a href="LibrarySource.html"><tt>LibrarySource</tt></a>s, respectively.
- * Each module also has a <a href="ModuleClassLoader.html"><tt>ModuleClassLoader</tt></a>
- * associated with it. The <tt>ModuleClassLoader</tt> consults these two types
- * of sources to find classes, resources, and native libraries.
- * </p>
- * @see org.apache.felix.moduleloader.ModuleManager
- * @see org.apache.felix.moduleloader.ModuleClassLoader
- * @see org.apache.felix.moduleloader.ResourceSource
- * @see org.apache.felix.moduleloader.LibrarySource
-**/
-public class Module
-{
- /**
- * This is the index used to retrieve the key of an attribute;
- * an attribute is represented as an <tt>Object[]</tt> instance.
- **/
- public static final int KEY_IDX = 0;
- /**
- * This is the index used to retrieve the value of an attribute;
- * an attribute is represented as an <tt>Object[]</tt> instance.
- **/
- public static final int VALUE_IDX = 1;
-
- private ModuleManager m_mgr = null;
- private String m_id = null;
- private boolean m_useParentSource = false;
- private Map m_attributeMap = new HashMap();
- private ResourceSource[] m_resSources = null;
- private LibrarySource[] m_libSources = null;
- private ModuleClassLoader m_loader = null;
-
- /**
- * <p>
- * Constructs a <tt>Module</tt> instance that will be associated with
- * the specified <tt>ModuleManager</tt> and will have the specified
- * identifier, attributes, resource sources, and library sources. In general,
- * modules should not be created directly, but should be created by making
- * a call to <tt>ModuleManager.addModule()</tt>.
- * </p>
- * @param mgr the <tt>ModuleManager</tt> that will be associated to
- * the instance.
- * @param id the identifier of the instance.
- * @param attributes the set of attributes associated with the instance.
- * @param resSources the set of <tt>ResourceSource</tt>s associated with
- * the instance.
- * @param libSources the set of <tt>LibrarySource</tt>s associated with
- * the instance.
- * @param useParentSource a flag indicating whether or not the parent
- * class loader should be used as a resource source; this is an
- * ugly hack to allow a module to masquerade as the system
- * class loader.
- * @see org.apache.felix.moduleloader.ModuleManager
- * @see org.apache.felix.moduleloader.ResourceSource
- * @see org.apache.felix.moduleloader.LibrarySource
- **/
- public Module(
- ModuleManager mgr, String id, Object[][] attributes,
- ResourceSource[] resSources, LibrarySource[] libSources,
- boolean useParentSource)
- {
- m_mgr = mgr;
- m_id = id;
- m_useParentSource = useParentSource;
- initialize(attributes, resSources, libSources);
- }
-
- /**
- * <p>
- * Returns the identifier of the module.
- * </p>
- * @return the identifier of the module.
- **/
- public String getId()
- {
- return m_id;
- }
-
- /**
- * <p>
- * Returns the attribute set associated with this module. Attributes
- * are represented as an array of <tt>Object</tt> arrays, i.e.,
- * <tt>Object[][]</tt>. Each element in the attribute array is
- * two-element <tt>Object</tt> array, where <tt>Module.KEY_IDX</tt>
- * is the index to the attribute key and <tt>Module.VALUE_IDX</tt>
- * is the index to the attribute value. The returned array is a
- * copy and may be freely modified.
- * </p>
- * @return the attribute set associated with this module.
- **/
- public synchronized Object[][] getAttributes()
- {
- Set s = m_attributeMap.entrySet();
- Object[][] attributes = new Object[s.size()][];
- Iterator iter = s.iterator();
- for (int i = 0; iter.hasNext(); i++)
- {
- Map.Entry entry = (Map.Entry) iter.next();
- attributes[i] = new Object[] { entry.getKey(), entry.getValue() };
- }
- return attributes;
- }
-
- /**
- * <p>
- * Returns the attribute value associated with the specified key.
- * </p>
- * @param key the key of the attribute whose value is to be retrieved.
- * @return the attribute's value or <tt>null</tt>.
- **/
- public synchronized Object getAttribute(String key)
- {
- return m_attributeMap.get(key);
- }
-
- /**
- * <p>
- * Sets the attribute value associated with the specified key. The
- * attribute will be added if it does not currently exist.
- * </p>
- * @param key the key of the attribute whose value is to be set.
- * @param value the new value to be associated with the attribute key.
- **/
- public synchronized void setAttribute(String key, Object value)
- {
- m_attributeMap.put(key, value);
- }
-
- /**
- * <p>
- * Returns the array of <tt>ResourceSource</tt>s associated with
- * the module. The returned array is not a copy and therefore should
- * not be modified.
- * </p>
- * @return the array of <tt>ResourceSource</tt>s associated with
- * the module.
- * @see org.apache.felix.moduleloader.ResourceSource
- **/
- public ResourceSource[] getResourceSources()
- {
- return m_resSources;
- }
-
- /**
- * <p>
- * Returns the array of <tt>LibrarySource</tt>s associated with
- * the module. The returned array is not a copy and therefore should
- * not be modified.
- * </p>
- * @return the array of <tt>LibrarySource</tt>s associated with
- * the module.
- * @see org.apache.felix.moduleloader.LibrarySource
- **/
- public LibrarySource[] getLibrarySources()
- {
- return m_libSources;
- }
-
- /**
- * <p>
- * Returns the <tt>ModuleClassLoader</tt> associated with this module.
- * If a security manager is installed, then this method uses a privileged
- * action to avoid a security exception being thrown to the caller.
- * </p>
- * @return the <tt>ModuleClassLoader</tt> associated with this module.
- * @see org.apache.felix.moduleloader.ModuleClassLoader
- **/
- public synchronized ModuleClassLoader getClassLoader()
- {
- if (m_loader == null)
- {
- if (System.getSecurityManager() != null)
- {
- m_loader = (ModuleClassLoader) AccessController.doPrivileged(
- new GetClassLoaderPrivileged(m_mgr, this, m_useParentSource));
- }
- else
- {
- m_loader = new ModuleClassLoader(m_mgr, this, m_useParentSource);
- }
- }
-
- return m_loader;
- }
-
- /**
- * <p>
- * Returns the module's identifier.
- * </p>
- * @return the module's identifier.
- **/
- public String toString()
- {
- return m_id;
- }
-
- /**
- * <p>
- * Resets the module by throwing away its associated class loader and
- * re-initializing its attributes, resource sources, and library sources
- * with the specified values.
- * </p>
- * @param attributes the new attributes to be associated with the module.
- * @param resSources the new resource sources to be associated with the module.
- * @param libSources the new library sources to be associated with the module.
- * @see org.apache.felix.moduleloader.ResourceSource
- * @see org.apache.felix.moduleloader.LibrarySource
- **/
- protected synchronized void reset(
- Object[][] attributes, ResourceSource[] resSources,
- LibrarySource[] libSources)
- {
- // Throw away class loader.
- m_loader = null;
- // Clear attribute map.
- m_attributeMap.clear();
- // Close all sources.
- dispose();
- // Re-initialize.
- initialize(attributes, resSources, libSources);
- }
-
- /**
- * <p>
- * Disposes the module by closing all resource and library sources.
- * </p>
- **/
- protected synchronized void dispose()
- {
- // Close sources.
- for (int i = 0; (m_resSources != null) && (i < m_resSources.length); i++)
- {
- m_resSources[i].close();
- }
- for (int i = 0; (m_libSources != null) && (i < m_libSources.length); i++)
- {
- m_libSources[i].close();
- }
- }
-
- /**
- * <p>
- * Initializes the module by copying the specified attribute array into
- * a map and opening all resource and library sources.
- * </p>
- * @param attributes the attributes to be put into a map.
- * @param resSources the resource sources to be opened.
- * @param libSources the library sources to be opened.
- * @see org.apache.felix.moduleloader.ResourceSource
- * @see org.apache.felix.moduleloader.LibrarySource
- **/
- private void initialize(
- Object[][] attributes, ResourceSource[] resSources, LibrarySource[] libSources)
- {
- for (int i = 0; (attributes != null) && (i < attributes.length); i++)
- {
- m_attributeMap.put(attributes[i][KEY_IDX], attributes[i][VALUE_IDX]);
- }
-
- m_resSources = resSources;
- m_libSources = libSources;
-
- // Open sources.
- for (int i = 0; (m_resSources != null) && (i < m_resSources.length); i++)
- {
- m_resSources[i].open();
- }
- for (int i = 0; (m_libSources != null) && (i < m_libSources.length); i++)
- {
- m_libSources[i].open();
- }
- }
-
- private static class GetClassLoaderPrivileged implements PrivilegedAction
- {
- private ModuleManager m_mgr = null;
- private Module m_module = null;
- private boolean m_useParentSource = false;
-
- public GetClassLoaderPrivileged(ModuleManager mgr, Module module, boolean useParentSource)
- {
- m_mgr = mgr;
- m_module = module;
- m_useParentSource = useParentSource;
- }
-
- public Object run()
- {
- return new ModuleClassLoader(m_mgr, m_module, m_useParentSource);
- }
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleClassLoader.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleClassLoader.java
deleted file mode 100644
index 5585979..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleClassLoader.java
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.io.IOException;
-import java.net.URL;
-import java.security.CodeSource;
-import java.security.SecureClassLoader;
-import java.security.cert.Certificate;
-import java.util.Enumeration;
-import java.util.Vector;
-
-/**
- * <p>
- * Each module that is managed by a <tt>ModuleManager</tt> has a
- * <tt>ModuleClassLoader</tt> associated with it. The <tt>ModuleClassLoader</tt>
- * is responsible for loading all classes, resources, and native libraries
- * for its module. The <tt>ModuleClassLoader</tt> of a module
- * is accessed using the <tt>Module.getClassLoader()</tt> method. The
- * <tt>ModuleClassLoader</tt> uses its module's
- * <a href="ResourceSource.html"><tt>ResourceSource</tt></a>s
- * and <a href="LibrarySource.html"><tt>LibrarySource</tt></a>s
- * to perform its function.
- * </p>
- * <p>
- * When loading a class or resource, the <tt>ModuleClassLoader</tt> does
- * not immediately search its module's <tt>ResourceSource</tt>s, instead
- * it first delegates the request to the
- * <a href="SearchPolicy.html"><tt>SearchPolicy</tt></a> of the
- * <tt>ModuleManager</tt>; this allows applications to inject specific
- * class/resource loading policies. When the <tt>ModuleClassLoader</tt> delegates
- * to the search policy, the search policy uses application-specific behavior
- * to typically service the request from the <tt>ResourceSource</tt>s of
- * other modules. If the search policy returns a result, then this result is
- * returned immediately by the <tt>ModuleClassLoader</tt>; otherwise, it searches
- * the <tt>ResourceSource</tt>s its module in an attempt to satisfy the
- * original request.
- * </p>
- * <p>
- * <b><i>Important:</i></b> The search policy <i>searches</i> modules in
- * some application-specific manner in order to find a class or resource.
- * This <i>search</i> is instigated, either directly or indirectly, by calls
- * to <tt>ModuleClassLoader.loadClass()</tt> and <tt>ModuleClassLoader.getResource()</tt>,
- * respectively. In order for the search policy to load a class or resource,
- * it must <b>not</b> use <tt>ModuleClassLoader.loadClass()</tt> or
- * <tt>ModuleClassLoader.getResource()</tt> again, because this would result
- * in an infinite loop. Instead, the <tt>ModuleClassLoader</tt> offers the
- * the methods <tt>ModuleClassLoader.loadClassFromModule()</tt> and
- * <tt>ModuleClassLoader.getResourceFromModule()</tt> to search a given module
- * and to avoid an infinite loop. As an example, consider the following
- * snippet of code that implements an "exhaustive" search policy:
- * </p>
- * <pre>
- * ...
- * public Class findClass(Module module, String name)
- * {
- * Module[] modules = m_mgr.getModules();
- * for (int i = 0; i < modules.length; i++)
- * {
- * try {
- * Class clazz = modules[i].getClassLoader().loadClassFromModule(name);
- * if (clazz != null)
- * {
- * return clazz;
- * }
- * } catch (Throwable th) {
- * }
- * }
- *
- * return null;
- * }
- * ...
- * </pre>
- * <p>
- * In the above code, the search policy "exhaustively" searches every module in the
- * <tt>ModuleManager</tt> to find the requested resource. Note that this policy
- * will also search the module that originated the request, which is not totally
- * necessary since returning <tt>null</tt> will cause the <tt>ModuleClassLoader</tt>
- * to search the originating module's <tt>ResourceSource</tt>s.
- * </p>
-**/
-public class ModuleClassLoader extends SecureClassLoader
-{
- private ModuleManager m_mgr = null;
- private Module m_module = null;
- private boolean m_useParentSource = false;
-
- /**
- * <p>
- * Constructs an instance using the specified <tt>ModuleManager</tt>, for
- * the specified <tt>Module</tt>. This constructor is protected so that
- * it cannot be created publicly.
- * </p>
- * @param mgr the <tt>ModuleManager</tt> of the <tt>Module</tt>.
- * @param module the <tt>Module</tt> instance associated with the class loader.
- **/
- protected ModuleClassLoader(ModuleManager mgr, Module module, boolean useParentSource)
- {
- super(ModuleClassLoader.class.getClassLoader());
- m_mgr = mgr;
- m_module = module;
- m_useParentSource = useParentSource;
- }
-
- /**
- * <p>
- * This method is only used by a framework instance so that it can determine
- * if a given module class loader is for a module of a bundle inside of it;
- * this is used for the URL Handlers service implementation.
- * </p>
- * @return <tt>true</tt> if the specified module manager is the same as
- * the one associated with this module class loader.
- **/
- public boolean isModuleManagerEqual(ModuleManager mgr)
- {
- return m_mgr == mgr;
- }
-
- /**
- * <p>
- * This method is nearly an exact copy of the ClassLoader.loadClass()
- * method. The main difference is that it delegates to its associated
- * <tt>ModuleManager</tt>'s search policy before calling the
- * <tt>ClassLoader.findClass()</tt> method. Additionally, the synchronized
- * modifier was removed from the superclass method; this change was necessary
- * because ClassLoader class assumes a tree of class loaders, but the class
- * loading structure in the <tt>ModuleManager</tt> might actually be a graph
- * of class loaders; thus, it was necessary to loosen the concurrency locking
- * to allow for cycles.
- * </p>
- * @param name the class to be loaded.
- * @param resolve flag indicating whether the class should be resolved or not.
- * @return the loaded class.
- * @throws java.lang.ClassNotFoundException if the class could not be loaded.
- **/
- protected Class loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- // Make sure the class was not already loaded.
- Class c = findLoadedClass(name);
- // Ask the search policy for the clas before consulting the module.
- c = m_mgr.getSearchPolicy().findClassBeforeModule(getParent(), m_module, name);
- // If the search policy didn't find it, then consult the module.
- if (c == null)
- {
- c = findClass(name);
- }
- // If the module didn't find it, then consult the search policy
- // one more time.
- if (c == null)
- {
- c = m_mgr.getSearchPolicy().findClassAfterModule(getParent(), m_module, name);
- }
- // If still not found, then throw an exception.
- if (c == null)
- {
- throw new ClassNotFoundException(name);
- }
- // Otherwise resolve the class.
- if (resolve)
- {
- resolveClass(c);
- }
- return c;
- }
-
- /**
- * <p>
- * This method overriden from from <tt>ClassLoader</tt>.
- * It is implemented such that it loads classes from the set of
- * <tt>ResourceSource</tt>s from its associated module.
- * </p>
- * @param name the name of the resource to load.
- * @return the loaded <tt>Class</tt> object.
- * @throws java.lang.ClassNotFoundException if the class could not be loaded.
- **/
- protected Class findClass(String name) throws ClassNotFoundException
- {
- Class clazz = findLoadedClass(name);
-
- // If the parent is used as a source, try to
- // load the class from it.
- // TODO: This is really a hack and should be generalized somehow.
- if (m_useParentSource)
- {
- clazz = (getParent() == null) ? null : getParent().loadClass(name);
- }
-
- // Otherwise search for class in resource sources.
- if (clazz == null)
- {
- String actual = name.replace('.', '/') + ".class";
- ResourceSource[] sources = m_module.getResourceSources();
- for (int i = 0;
- (clazz == null) && (sources != null) && (i < sources.length);
- i++)
- {
- byte[] bytes = sources[i].getBytes(actual);
- if (bytes != null)
- {
- // We need to try to define a Package object for the class
- // before we call defineClass(). Get the package name and
- // see if we have already created the package.
- String pkgName = Util.getClassPackage(name);
- if (pkgName.length() > 0)
- {
- if (getPackage(pkgName) == null)
- {
- Object[] params =
- m_mgr.getSearchPolicy().definePackage(m_module, pkgName);
- if (params != null)
- {
- definePackage(
- pkgName,
- (String) params[0],
- (String) params[1],
- (String) params[2],
- (String) params[3],
- (String) params[4],
- (String) params[5],
- null);
- }
- else
- {
- definePackage(pkgName, null, null,
- null, null, null, null, null);
- }
- }
- }
-
- // Get the code source URL for this class. For concurrency
- // purposes, we are performing this call outside of the
- // synchronized block below since we call out to application
- // code, which might in turn need to call back into the
- // module loader code. Because of this, it is better to
- // not be holding any locks before making the call.
- URL url = m_mgr.getURLPolicy().createCodeSourceURL(
- m_mgr, m_module);
-
- // If we have a valid code source URL, then use it to
- // define the class for security purposes, otherwise
- // define the class without a code source.
- if (url != null)
- {
- CodeSource cs = new CodeSource(url, (Certificate[]) null);
- clazz = defineClass(name, bytes, 0, bytes.length, cs);
- }
- else
- {
- clazz = defineClass(name, bytes, 0, bytes.length);
- }
- }
- }
- }
-
- if (clazz != null)
- {
- return clazz;
- }
-
- return null;
- }
-
- /**
- * <p>
- * This method is used by <tt>SearchPolicy</tt> instances when they want
- * to load a class from a module. The search policy is initially invoked when
- * <tt>ModuleClassLoader.loadClass()</tt> delegates a class loading
- * request to it. In general, the ultimate goal of the search policy is to
- * return a class from another module if possible. Unfortunately, if a search
- * policy tries to directly load a class from another module's class loader, an
- * infinite loop will result because the module's class loader will delegate the
- * request back to the search policy. To avoid this situation, search policies
- * must use this method when trying to load a class from a module.
- * </p>
- * @param name the name of the class to load.
- * @return the loaded class or <tt>null</tt>.
- **/
- public Class loadClassFromModule(String name)
- {
- try
- {
- return findClass(name);
- } catch (Throwable th) {
- // Not much we can do.
-// TODO: Do something with this error message.
-// System.err.println("ModuleClassLoader: " + th.getMessage());
- }
- return null;
- }
-
- /**
- * <p>
- * This method is nearly an exact copy of the ClassLoader.getResource()
- * method. The main difference is that it delegates to its associated
- * <tt>ModuleManager</tt>'s search policy before calling the
- * <tt>ClassLoader.findResource()</tt> method.
- * </p>
- * @param name the class to be loaded.
- * @return a URL to the resource or <tt>null</tt> if the resource was not found.
- **/
- public URL getResource(String name)
- {
- URL url = null;
-
- // Ask the search policy for the resource.
- if (m_mgr.getSearchPolicy() != null)
- {
- try
- {
- url = m_mgr.getSearchPolicy().findResource(getParent(), m_module, name);
- }
- catch (ResourceNotFoundException ex)
- {
- // We return null here because if SearchPolicy.findResource()
- // throws an exception we interpret that to mean that the
- // search should be stopped.
- return null;
- }
- }
-
- // If not found, then search locally.
- if (url == null)
- {
- url = findResource(name);
- }
-
- return url;
- }
-
- /**
- * <p>
- * This method overriden from from <tt>ClassLoader</tt>.
- * It is implemented such that it loads resources from the set of
- * <tt>ResourceSource</tt>s from its associated module.
- * </p>
- * @param name the name of the resource to load.
- * @return the <tt>URL</tt> associated with the resource or <tt>null</tt>.
- **/
- protected URL findResource(String name)
- {
- URL url = null;
-
- // If the parent is used as a source, try to
- // load the class from it.
- if (m_useParentSource)
- {
- url = (getParent() == null) ? null : getParent().getResource(name);
- }
-
- // Try to load the resource from the module's resource
- // sources.
- if (url == null)
- {
- // Remove leading slash, if present.
- if (name.startsWith("/"))
- {
- name = name.substring(1);
- }
-
- ResourceSource[] sources = m_module.getResourceSources();
- for (int i = 0;
- (url == null) && (sources != null) && (i < sources.length);
- i++)
- {
- if (sources[i].hasResource(name))
- {
- url = m_mgr.getURLPolicy().createResourceURL(m_mgr, m_module, i, name);
- }
- }
- }
-
- return url;
- }
-
- /**
- * <p>
- * This method is used by <tt>SearchPolicy</tt> instances when they want
- * to load a resource from a module. The search policy is initially invoked when
- * <tt>ModuleClassLoader.loadClass()</tt> delegates a resource loading
- * request to it. In general, the ultimate goal of the search policy is to
- * return a resource from another module if possible. Unfortunately, if a search
- * policy tries to directly load a resource from another module's class loader, an
- * infinite loop will result because the module's class loader will delegate the
- * request back to the search policy. To avoid this situation, search policies
- * must use this method when trying to load a resource from a module.
- * </p>
- * @param name the name of the resource to load.
- * @return a URL to the resource or <tt>null</tt>.
- **/
- public URL getResourceFromModule(String name)
- {
- try
- {
- return findResource(name);
- }
- catch (Throwable th)
- {
- // Ignore and just return null.
- }
- return null;
- }
-
- protected Enumeration findResources(String name)
- {
- Vector v = new Vector();
- // If the parent is used as a source, try to
- // load the class from it.
- if (m_useParentSource)
- {
- try
- {
- Enumeration e = (getParent() == null)
- ? null : getParent().getResources(name);
- while ((e != null) && e.hasMoreElements())
- {
- v.addElement(e.nextElement());
- }
- }
- catch (IOException ex)
- {
- // What can we do?
- }
- }
-
- // Remove leading slash, if present.
- if (name.startsWith("/"))
- {
- name = name.substring(1);
- }
-
- // Try to load the resource from the module's resource
- // sources.
-
- ResourceSource[] sources = m_module.getResourceSources();
- for (int i = 0; (sources != null) && (i < sources.length); i++)
- {
- if (sources[i].hasResource(name))
- {
- v.addElement(m_mgr.getURLPolicy().createResourceURL(m_mgr, m_module, i, name));
- }
- }
-
- return v.elements();
- }
-
- /**
- * <p>
- * This method overriden from from <tt>ClassLoader</tt>. It maps a library
- * name to a library path by consulting the <tt>LibrarySource</tt>s of the
- * class loader's module.
- * </p>
- * @param name the name of the library to find.
- * @return the file system path of library or <tt>null</tt>
- **/
- protected String findLibrary(String name)
- {
- // Remove leading slash, if present.
- if (name.startsWith("/"))
- {
- name = name.substring(1);
- }
-
- LibrarySource[] sources = m_module.getLibrarySources();
- for (int i = 0;
- (sources != null) && (i < sources.length);
- i++)
- {
- String path = sources[i].getPath(name);
- if (path != null)
- {
- return path;
- }
- }
-
- return null;
- }
-}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleEvent.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleEvent.java
index ec15d49..8a00403 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleEvent.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleEvent.java
@@ -25,13 +25,13 @@
* events, a <tt>ModuleListener</tt> must be added to the <tt>ModuleManager</tt>
* instance.
* </p>
- * @see org.apache.felix.moduleloader.ModuleManager
- * @see org.apache.felix.moduleloader.Module
+ * @see org.apache.felix.moduleloader.ModuleFactoryImpl
+ * @see org.apache.felix.moduleloader.ModuleImpl
* @see org.apache.felix.moduleloader.ModuleListener
**/
public class ModuleEvent extends EventObject
{
- private Module m_module = null;
+ private IModule m_module = null;
/**
* <p>
@@ -42,9 +42,9 @@
* @param mgr the source of the event.
* @param module the subject of the event.
**/
- public ModuleEvent(ModuleManager mgr, Module module)
+ public ModuleEvent(IModuleFactory factory, IModule module)
{
- super(mgr);
+ super(factory);
m_module = module;
}
@@ -54,7 +54,7 @@
* </p>
* @return the module that is the subject of the event.
**/
- public Module getModule()
+ public IModule getModule()
{
return m_module;
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java
new file mode 100644
index 0000000..84cfd67
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.moduleloader;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.framework.Logger;
+
+public class ModuleFactoryImpl implements IModuleFactory
+{
+ private Logger m_logger = null;
+ private Map m_moduleMap = new HashMap();
+
+ private ModuleListener[] m_listeners = null;
+ private static final ModuleListener[] m_noListeners = new ModuleListener[0];
+
+ public ModuleFactoryImpl(Logger logger)
+ {
+ m_logger = logger;
+ m_listeners = m_noListeners;
+ }
+
+ public synchronized IModule[] getModules()
+ {
+ return (IModule[]) m_moduleMap.values().toArray(new IModule[m_moduleMap.size()]);
+ }
+
+ public synchronized IModule getModule(String id)
+ {
+ return (IModule) m_moduleMap.get(id);
+ }
+
+ public IModule createModule(String id)
+ {
+ IModule module = null;
+
+ // Use a synchronized block instead of synchronizing the
+ // method, so we can fire our event outside of the block.
+ synchronized (this)
+ {
+ if (m_moduleMap.get(id) == null)
+ {
+ module = new ModuleImpl(m_logger, id);
+ m_moduleMap.put(id, module);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Module ID must be unique.");
+ }
+ }
+
+ // Fire event here instead of inside synchronized block.
+ fireModuleAdded(module);
+
+ return module;
+ }
+
+ public void removeModule(IModule module)
+ {
+ // Use a synchronized block instead of synchronizing the
+ // method, so we can fire our event outside of the block.
+ synchronized (this)
+ {
+ if (m_moduleMap.get(module.getId()) != null)
+ {
+ // Remove from data structures.
+ m_moduleMap.remove(module.getId());
+ // Close the module's content loader to deinitialize it.
+ // TODO: This is not really the best place for this, but at
+ // least it is centralized with the call to IContentLoader.open()
+ // when a module's content loader is set below.
+ ((ModuleImpl) module).getContentLoader().close();
+ }
+ else
+ {
+ // Don't fire event.
+ return;
+ }
+ }
+
+ // Fire event here instead of inside synchronized block.
+ fireModuleRemoved(module);
+ }
+
+ public void setContentLoader(IModule module, IContentLoader contentLoader)
+ {
+ synchronized (this)
+ {
+ ((ModuleImpl) module).setContentLoader(contentLoader);
+ // Open the module's content loader to initialize it.
+ // TODO: This is not really the best place for this, but at
+ // least it is centralized with the call to IContentLoader.close()
+ // when the module is removed above.
+ contentLoader.open();
+ }
+ }
+
+ /**
+ * <p>
+ * Adds a listener to the <tt>IModuleFactory</tt> to listen for
+ * module added and removed events.
+ * </p>
+ * @param l the <tt>ModuleListener</tt> to add.
+ **/
+ public void addModuleListener(ModuleListener l)
+ {
+ // Verify listener.
+ if (l == null)
+ {
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ // Use the m_noListeners object as a lock.
+ synchronized (m_noListeners)
+ {
+ // If we have no listeners, then just add the new listener.
+ if (m_listeners == m_noListeners)
+ {
+ m_listeners = new ModuleListener[] { l };
+ }
+ // Otherwise, we need to do some array copying.
+ // Notice, the old array is always valid, so if
+ // the dispatch thread is in the middle of a dispatch,
+ // then it has a reference to the old listener array
+ // and is not affected by the new value.
+ else
+ {
+ ModuleListener[] newList = new ModuleListener[m_listeners.length + 1];
+ System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
+ newList[m_listeners.length] = l;
+ m_listeners = newList;
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Removes a listener from the <tt>IModuleFactory</tt>.
+ * </p>
+ * @param l the <tt>ModuleListener</tt> to remove.
+ **/
+ public void removeModuleListener(ModuleListener l)
+ {
+ // Verify listener.
+ if (l == null)
+ {
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ // Use the m_noListeners object as a lock.
+ synchronized (m_noListeners)
+ {
+ // Try to find the instance in our list.
+ int idx = -1;
+ for (int i = 0; i < m_listeners.length; i++)
+ {
+ if (m_listeners[i].equals(l))
+ {
+ idx = i;
+ break;
+ }
+ }
+
+ // If we have the instance, then remove it.
+ if (idx >= 0)
+ {
+ // If this is the last listener, then point to empty list.
+ if (m_listeners.length == 1)
+ {
+ m_listeners = m_noListeners;
+ }
+ // Otherwise, we need to do some array copying.
+ // Notice, the old array is always valid, so if
+ // the dispatch thread is in the middle of a dispatch,
+ // then it has a reference to the old listener array
+ // and is not affected by the new value.
+ else
+ {
+ ModuleListener[] newList = new ModuleListener[m_listeners.length - 1];
+ System.arraycopy(m_listeners, 0, newList, 0, idx);
+ if (idx < newList.length)
+ {
+ System.arraycopy(m_listeners, idx + 1, newList, idx,
+ newList.length - idx);
+ }
+ m_listeners = newList;
+ }
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Fires an event indicating that the specified module was added
+ * to the <tt>IModuleFactory</tt>.
+ * </p>
+ * @param module the module that was added.
+ **/
+ protected void fireModuleAdded(IModule module)
+ {
+ // Event holder.
+ ModuleEvent event = null;
+
+ // Get a copy of the listener array, which is guaranteed
+ // to not be null.
+ ModuleListener[] listeners = m_listeners;
+
+ // Loop through listeners and fire events.
+ for (int i = 0; i < listeners.length; i++)
+ {
+ // Lazily create event.
+ if (event == null)
+ {
+ event = new ModuleEvent(this, module);
+ }
+ listeners[i].moduleAdded(event);
+ }
+ }
+
+ /**
+ * <p>
+ * Fires an event indicating that the specified module was removed
+ * from the <tt>IModuleFactory</tt>.
+ * </p>
+ * @param module the module that was removed.
+ **/
+ protected void fireModuleRemoved(IModule module)
+ {
+ // Event holder.
+ ModuleEvent event = null;
+
+ // Get a copy of the listener array, which is guaranteed
+ // to not be null.
+ ModuleListener[] listeners = m_listeners;
+
+ // Loop through listeners and fire events.
+ for (int i = 0; i < listeners.length; i++)
+ {
+ // Lazily create event.
+ if (event == null)
+ {
+ event = new ModuleEvent(this, module);
+ }
+ listeners[i].moduleRemoved(event);
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
new file mode 100644
index 0000000..e7f6536
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.moduleloader;
+
+import java.net.URL;
+
+import org.apache.felix.framework.Logger;
+
+public class ModuleImpl implements IModule
+{
+ private Logger m_logger = null;
+ private String m_id = null;
+ private IContentLoader m_contentLoader = null;
+
+ ModuleImpl(Logger logger, String id)
+ {
+ m_logger = logger;
+ m_id = id;
+ }
+
+ public String getId()
+ {
+ return m_id;
+ }
+
+ public IContentLoader getContentLoader()
+ {
+ return m_contentLoader;
+ }
+
+ protected void setContentLoader(IContentLoader contentLoader)
+ {
+ m_contentLoader = contentLoader;
+ }
+
+ public Class getClass(String name)
+ {
+ try
+ {
+ return m_contentLoader.getSearchPolicy().findClass(name);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ m_logger.log(
+ Logger.LOG_WARNING,
+ ex.getMessage(),
+ ex);
+ }
+ return null;
+ }
+
+ public URL getResource(String name)
+ {
+ try
+ {
+ return m_contentLoader.getSearchPolicy().findResource(name);
+ }
+ catch (ResourceNotFoundException ex)
+ {
+ m_logger.log(
+ Logger.LOG_WARNING,
+ ex.getMessage(),
+ ex);
+ }
+ return null;
+ }
+
+ public String toString()
+ {
+ return m_id;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleListener.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleListener.java
index 4a583d9..813187a 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleListener.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@
* <p>
* This interface is an event listener for <tt>ModuleEvent</tt> events.
* To receive events, an implementation of this listener must be added
- * to the <tt>ModuleManager</tt> instance.
+ * to the <tt>IModuleFactory</tt> instance.
* </p>
- * @see org.apache.felix.moduleloader.ModuleManager
+ * @see org.apache.felix.moduleloader.IModuleFactory
* @see org.apache.felix.moduleloader.ModuleEvent
**/
public interface ModuleListener extends EventListener
@@ -32,7 +32,7 @@
/**
* <p>
* This method is called after a module is added to the
- * <tt>ModuleManager</tt>.
+ * <tt>IModuleFactory</tt>.
* </p>
* @param event the event object containing the event details.
**/
@@ -40,17 +40,8 @@
/**
* <p>
- * This method is called after a module has been reset by the
- * <tt>ModuleManager</tt>.
- * </p>
- * @param event the event object containing the event details.
- **/
- public void moduleReset(ModuleEvent event);
-
- /**
- * <p>
* This method is called after a module is remove from the
- * <tt>ModuleManager</tt>.
+ * <tt>IModuleFactory</tt>.
* </p>
* @param event the event object containing the event details.
**/
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleManager.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleManager.java
deleted file mode 100644
index 7640479..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleManager.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.util.*;
-
-/**
- * <p>
- * The <tt>ModuleManager</tt> class is the core facility for defining a
- * re-usable, policy-driven class loader for applications that require
- * flexible class loading mechanisms. The <tt>ModuleManager</tt> is not
- * class loader itself, but it supports the concept of a
- * <a href="Module.html"><tt>Module</tt></a>,
- * which is a unit of organization for application classes and resources.
- * The <tt>ModuleManager</tt> has only a handful of methods that allow
- * an application to add, remove, reset, and query modules; the intent
- * is to place as few assumptions in the <tt>ModuleManager</tt> as possible.
- * </p>
- * <p>
- * The idea is simple, allow the application to map itself into modules
- * however it sees fit and let the <tt>ModuleManager</tt> assume the
- * responsibility of managing the modules and loading classes and resources
- * from them as necessary via <a href="ModuleClassLoader.html"><tt>ModuleClassLoader</tt></a>s
- * that are associated with each module. In order to achieve this goal, though, the
- * <tt>ModuleManager</tt> must make at least one assumption on behalf of
- * the application. This assumption is that the loading of classes and resources
- * from the available modules must happen using a search algorithm
- * that is particular to the application itself. As a result of this assumption,
- * the <tt>ModuleManager</tt> requires that the application provide a concrete
- * implementation of the <a href="SearchPolicy.html"><tt>SearchPolicy</tt></a>
- * interface.
- * </p>
- * <p>
- * The search policy allows the <tt>ModuleLoader</tt> to let applications inject
- * their own particular class loading policies, without dictating strict or
- * constraining base assumptions. Of course, it is likely that many applications
- * will use the same or very similar search policies. Because of this, another
- * goal of the <tt>ModuleLoader</tt> approach is to foster a common library of
- * search policies that applications are free to use or customize as they see
- * fit. These common search policies are analagous to patterns, where each search
- * policy is viewable as a <i>class loading pattern</i>. Some initial search
- * policies included with the <tt>ModuleLoader</tt> are
- * <a href="search/ExhaustiveSearchPolicy.html"><tt>ExhaustiveSearchPolicy</tt></a>,
- * <a href="search/SelfContainedSearchPolicy.html"><tt>SelfContainedSearchPolicy</tt></a>, and
- * <a href="search/ImportSearchPolicy.html"><tt>ImportSearchPolicy</tt></a>.
- * </p>
- * <p>
- * Due to the fact that class loaders are tied to security and resource loading,
- * the search policy alone is not sufficient for the <tt>ModuleLoader</tt> to
- * perform its function. To fulfill these other purposes, the <tt>ModuleLoader</tt>
- * introduces another policy interface, called the <a href="URLPolicy.html"><tt>URLPolicy</tt></a>.
- * The <tt>URLPolicy</tt> allows the application to inject its particular policy
- * for to purposes:
- * </p>
- * <ol>
- * <li>Creating the <tt>URL</tt> associated with loading a resource, such as
- * the <tt>URL</tt> returned from a call to <tt>Class.getResource()</tt>.
- * </li>
- * <li>Creating the <tt>URL</tt> that will be associated with a class's
- * <tt>CodeSource</tt> when defining the class for purposes of security
- * and assigning permissions.
- * </li>
- * </ol>
- * <p>
- * The <tt>ModuleLoader</tt> defines a default <tt>URLPolicy</tt>, called
- * <a href="DefaultURLPolicy.html"><tt>DefaultURLPolicy</tt></a>, that provides
- * a simple <tt>URLStreamHandler</tt> for accessing resources inside of modules
- * and that returns <tt>null</tt> for the <tt>CodeSource</tt> <tt>URL</tt>.
- * Applications only need to supply their own <tt>URLPolicy</tt> if the default
- * one does not provide the appropriate behavior.
- * </p>
- * <p>
- * It is possible for an application to create multiple instances of the
- * <tt>ModuleManager</tt> within a single JVM, but it is not possible to
- * share modules across multiple <tt>ModuleManager</tt>s. A given <tt>ModuleManager</tt>
- * can only have one <tt>SelectionPolicy</tt> and one <tt>URLPolicy</tt>.
- * </p>
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ModuleClassLoader
- * @see org.apache.felix.moduleloader.SearchPolicy
- * @see org.apache.felix.moduleloader.URLPolicy
- * @see org.apache.felix.moduleloader.DefaultURLPolicy
-**/
-public class ModuleManager
-{
- private List m_moduleList = new ArrayList();
- private Map m_moduleMap = new HashMap();
- private SearchPolicy m_searchPolicy = null;
- private URLPolicy m_urlPolicy = null;
- private ModuleListener[] m_listeners = null;
- private static final ModuleListener[] m_noListeners = new ModuleListener[0];
-
- /**
- * <p>
- * Constructs a <tt>ModuleManager</tt> instance using the specified
- * search policy and the default <tt>URL</tt> policy.
- * </p>
- * @param searchPolicy the search policy that the instance should use.
- * @see org.apache.felix.moduleloader.SearchPolicy
- **/
- public ModuleManager(SearchPolicy searchPolicy)
- {
- this(searchPolicy, null);
- }
-
- /**
- * <p>
- * Constructs a <tt>ModuleManager</tt> instance using the specified
- * search policy and the specified <tt>URL</tt> policy.
- * </p>
- * @param searchPolicy the search policy that the instance should use.
- * @param urlPolicy the <tt>URL</tt> policy that the instance should use.
- * @see org.apache.felix.moduleloader.SearchPolicy
- * @see org.apache.felix.moduleloader.URLPolicy
- **/
- public ModuleManager(SearchPolicy searchPolicy, URLPolicy urlPolicy)
- {
- m_listeners = m_noListeners;
- m_searchPolicy = searchPolicy;
- m_searchPolicy.setModuleManager(this);
-
- if (urlPolicy == null)
- {
- m_urlPolicy = new DefaultURLPolicy();
- }
- else
- {
- m_urlPolicy = urlPolicy;
- }
- }
-
- /**
- * <p>
- * Returns the <tt>URL</tt> policy used by this instance.
- * </p>
- * @return the <tt>URL</tt> policy used by this instance.
- * @see org.apache.felix.moduleloader.URLPolicy
- **/
- public URLPolicy getURLPolicy()
- {
- return m_urlPolicy;
- }
-
- /**
- * <p>
- * Returns the search policy used by this instance.
- * </p>
- * @return the search policy used by this instance.
- * @see org.apache.felix.moduleloader.SearchPolicy
- **/
- public SearchPolicy getSearchPolicy()
- {
- return m_searchPolicy;
- }
-
- /**
- * <p>
- * Returns an array of all modules being managed by the
- * <tt>ModuleManager</tt> instance. The array contains a snapshot of
- * all modules in the <tt>ModuleManager</tt> at the time when this
- * method was called.
- * </p>
- * @return an array of all modules being managed by the <tt>ModuleManager</tt>
- * instance.
- * @see org.apache.felix.moduleloader.Module
- **/
- public synchronized Module[] getModules()
- {
- Module[] modules = new Module[m_moduleList.size()];
- return (Module[]) m_moduleList.toArray(modules);
- }
-
- /**
- * <p>
- * Returns a module associated with the specified identifier.
- * </p>
- * @param id the identifier for the module to be retrieved.
- * @return the module associated with the identifier or <tt>null</tt>.
- * @see org.apache.felix.moduleloader.Module
- **/
- public synchronized Module getModule(String id)
- {
- return (Module) m_moduleMap.get(id);
- }
-
- /**
- * <p>
- * Adds a module to the module manager. The module will have the specified
- * unique identifier, with the associated attributes, resource sources, and
- * library sources. If the identifier is not unique, then an exception is
- * thrown.
- * </p>
- * @param id the unique identifier of the new module.
- * @param attributes an array of key-value attribute pairs to
- * associate with the module.
- * @param resSources an array of <tt>ResourceSource</tt>s to associate
- * with the module.
- * @param libSources an array of <tt>LibrarySource</tt>s to associate
- * with the module.
- * @return the newly created module.
- * @throws java.lang.IllegalArgumentException if the module identifier
- * is not unique.
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ResourceSource
- * @see org.apache.felix.moduleloader.LibrarySource
- **/
- public Module addModule(String id, Object[][] attributes,
- ResourceSource[] resSources, LibrarySource[] libSources)
- {
- return addModule(id, attributes, resSources, libSources, false);
- }
-
- public Module addModule(String id, Object[][] attributes,
- ResourceSource[] resSources, LibrarySource[] libSources,
- boolean useParentSource)
- {
- Module module = null;
-
- // Use a synchronized block instead of synchronizing the
- // method, so we can fire our event outside of the block.
- synchronized (this)
- {
- if (m_moduleMap.get(id) == null)
- {
- module = new Module(this, id, attributes, resSources, libSources, useParentSource);
- m_moduleList.add(module);
- m_moduleMap.put(id, module);
- }
- else
- {
- throw new IllegalArgumentException("Module ID must be unique.");
- }
- }
-
- // Fire event here instead of inside synchronized block.
- fireModuleAdded(module);
-
- return module;
- }
-
- /**
- * <p>
- * Resets a given module. In resetting a module, the module's associated
- * class loader is thrown away; it is the application's responsibility to
- * determine when and how that application code stops using classes (and
- * subsequent instances) from the class loader of the reset module.
- * This method allows the associated elements of the module (i.e.,
- * attributes, resource sources, and library sources) to be changed also;
- * if these elements have not changed then they simply need to be passed
- * back in from the existing module. This method is useful in situations
- * where the underlying module needs to be changed at run time, such as
- * might be necessary if a module was updated.
- * </p>
- * <p>
- * The same effect could be achieved by first removing and then re-adding
- * a module, but with one subtle different. By removing and then re-adding
- * a module, a new module is created and, thus, all existing references
- * become invalid. By explicitly having this method, the <tt>ModuleManager</tt>
- * maintains the integrity of the module reference, which is more intuitive
- * in the case where an updated module is intended to be the same module,
- * only updated.
- * </p>
- * @param module the module reset.
- * @param attributes an array of key-value attribute pairs to
- * associate with the module.
- * @param resSources an array of <tt>ResourceSource</tt>s to associate
- * with the module.
- * @param libSources an array of <tt>LibrarySource</tt>s to associate
- * with the module.
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ResourceSource
- * @see org.apache.felix.moduleloader.LibrarySource
- **/
- public void resetModule(
- Module module, Object[][] attributes,
- ResourceSource[] resSources, LibrarySource[] libSources)
- {
- // Use a synchronized block instead of synchronizing the
- // method, so we can fire our event outside of the block.
- synchronized (this)
- {
- module = (Module) m_moduleMap.get(module.getId());
- if (module != null)
- {
- module.reset(attributes, resSources, libSources);
- }
- else
- {
- // Don't fire event.
- return;
- }
- }
-
- // Fire event here instead of inside synchronized block.
- fireModuleReset(module);
- }
-
- /**
- * <p>
- * Removes the specified module from the <tt>ModuleManager</tt>. Removing
- * a module only removed the module from the <tt>ModuleManager</tt>. It is
- * the application's responsibility to determine when and how application code
- * stop using classes (and subsequent instances) that were loaded from
- * the class loader of the removed module.
- * </p>
- * @param module the module to remove.
- **/
- public void removeModule(Module module)
- {
- // Use a synchronized block instead of synchronizing the
- // method, so we can fire our event outside of the block.
- synchronized (this)
- {
- if (m_moduleMap.get(module.getId()) != null)
- {
- // Remove from data structures.
- m_moduleList.remove(module);
- m_moduleMap.remove(module.getId());
-
- // Dispose of the module.
- module.dispose();
- }
- else
- {
- // Don't fire event.
- return;
- }
- }
-
- // Fire event here instead of inside synchronized block.
- fireModuleRemoved(module);
- }
-
- /**
- * <p>
- * Adds a listener to the <tt>ModuleManager</tt> to listen for
- * module added, reset, and removed events.
- * </p>
- * @param l the <tt>ModuleListener</tt> to add.
- **/
- public void addModuleListener(ModuleListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
-
- // Use the m_noListeners object as a lock.
- synchronized (m_noListeners)
- {
- // If we have no listeners, then just add the new listener.
- if (m_listeners == m_noListeners)
- {
- m_listeners = new ModuleListener[] { l };
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- ModuleListener[] newList = new ModuleListener[m_listeners.length + 1];
- System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
- newList[m_listeners.length] = l;
- m_listeners = newList;
- }
- }
- }
-
- /**
- * <p>
- * Removes a listener from the <tt>ModuleManager</tt>.
- * </p>
- * @param l the <tt>ModuleListener</tt> to remove.
- **/
- public void removeModuleListener(ModuleListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
-
- // Use the m_noListeners object as a lock.
- synchronized (m_noListeners)
- {
- // Try to find the instance in our list.
- int idx = -1;
- for (int i = 0; i < m_listeners.length; i++)
- {
- if (m_listeners[i].equals(l))
- {
- idx = i;
- break;
- }
- }
-
- // If we have the instance, then remove it.
- if (idx >= 0)
- {
- // If this is the last listener, then point to empty list.
- if (m_listeners.length == 1)
- {
- m_listeners = m_noListeners;
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- ModuleListener[] newList = new ModuleListener[m_listeners.length - 1];
- System.arraycopy(m_listeners, 0, newList, 0, idx);
- if (idx < newList.length)
- {
- System.arraycopy(m_listeners, idx + 1, newList, idx,
- newList.length - idx);
- }
- m_listeners = newList;
- }
- }
- }
- }
-
- /**
- * <p>
- * Fires an event indicating that the specified module was added
- * to the <tt>ModuleManager</tt>.
- * </p>
- * @param module the module that was added.
- **/
- protected void fireModuleAdded(Module module)
- {
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ModuleListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(this, module);
- }
- listeners[i].moduleAdded(event);
- }
- }
-
- /**
- * <p>
- * Fires an event indicating that the specified module was reset.
- * </p>
- * @param module the module that was reset.
- **/
- protected void fireModuleReset(Module module)
- {
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ModuleListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(this, module);
- }
- listeners[i].moduleReset(event);
- }
- }
-
- /**
- * <p>
- * Fires an event indicating that the specified module was removed
- * from the <tt>ModuleManager</tt>.
- * </p>
- * @param module the module that was removed.
- **/
- protected void fireModuleRemoved(Module module)
- {
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ModuleListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(this, module);
- }
- listeners[i].moduleRemoved(event);
- }
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLConnection.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLConnection.java
deleted file mode 100644
index 9015bbf..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ModuleURLConnection.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.io.*;
-import java.net.URL;
-import java.net.URLConnection;
-import java.security.Permission;
-
-class ModuleURLConnection extends URLConnection
-{
- private ModuleManager m_mgr = null;
- private int m_contentLength;
- private long m_contentTime;
- private String m_contentType;
- private InputStream m_is;
-
- public ModuleURLConnection(ModuleManager mgr, URL url)
- {
- super(url);
- m_mgr = mgr;
- }
-
- public void connect() throws IOException
- {
- if (!connected)
- {
- // The URL is constructed like this:
- // module://<module-id>/<source-idx>/<resource-path>
- Module module = m_mgr.getModule(url.getHost());
- if (module == null)
- {
- throw new IOException("Unable to find bundle's module.");
- }
-
- String resource = url.getFile();
- if (resource == null)
- {
- throw new IOException("Unable to find resource: " + url.toString());
- }
- if (resource.startsWith("/"))
- {
- resource = resource.substring(1);
- }
- int rsIdx = -1;
- try
- {
- rsIdx = Integer.parseInt(resource.substring(0, resource.indexOf("/")));
- }
- catch (NumberFormatException ex)
- {
- new IOException("Error parsing resource index.");
- }
- resource = resource.substring(resource.indexOf("/") + 1);
-
- // Get the resource bytes from the resource source.
- byte[] bytes = null;
- ResourceSource[] resSources = module.getResourceSources();
- if ((resSources != null) && (rsIdx < resSources.length))
- {
- if (resSources[rsIdx].hasResource(resource))
- {
- bytes = resSources[rsIdx].getBytes(resource);
- }
- }
-
- if (bytes == null)
- {
- throw new IOException("Unable to find resource: " + url.toString());
- }
-
- m_is = new ByteArrayInputStream(bytes);
- m_contentLength = bytes.length;
- m_contentTime = 0L; // TODO: Change this.
- m_contentType = URLConnection.guessContentTypeFromName(resource);
- connected = true;
- }
- }
-
- public InputStream getInputStream()
- throws IOException
- {
- if (!connected)
- {
- connect();
- }
- return m_is;
- }
-
- public int getContentLength()
- {
- if (!connected)
- {
- try {
- connect();
- } catch(IOException ex) {
- return -1;
- }
- }
- return m_contentLength;
- }
-
- public long getLastModified()
- {
- if (!connected)
- {
- try {
- connect();
- } catch(IOException ex) {
- return 0;
- }
- }
- if (m_contentTime != -1L)
- {
- return m_contentTime;
- }
- else
- {
- return 0L;
- }
- }
-
- public String getContentType()
- {
- if (!connected)
- {
- try {
- connect();
- } catch(IOException ex) {
- return null;
- }
- }
- return m_contentType;
- }
-
- public Permission getPermission()
- {
- // TODO: This should probably return a FilePermission
- // to access the bundle JAR file, but we don't have the
- // necessary information here to construct the absolute
- // path of the JAR file...so it would take some
- // re-arranging to get this to work.
- return null;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ResourceSource.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ResourceSource.java
deleted file mode 100644
index 78d1ee1..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ResourceSource.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-/**
- * <p>
- * This interface represents a source for obtaining resources for a
- * given module via the module's class loader. A resource source is used
- * for retrieving both classes and resources; at this level, classes are
- * treated in an identical manner as an ordinary resource. Resource sources
- * are completely arbitrary and implementations may load resources from a JAR
- * file, the network, a database, or anywhere.
- * </p>
- * <p>
- * All resource sources are initialized before first usage via a call
- * to the <a href="#open()"><tt>ResourceSource.open()</tt></a> method and
- * are also deinitialized via a call to
- * <a href="#open()"><tt>ResourceSource.close()</tt></a>. Resource sources
- * should be implemented such that they can be opened, closed, and then
- * re-opened.
- * </p>
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ModuleClassLoader
-**/
-public interface ResourceSource
-{
- /**
- * <p>
- * This method initializes the resource source. It is called when
- * the associated module is added to the <tt>ModuleManager</tt>. It
- * is acceptable for implementations to ignore duplicate calls to this
- * method if the resource source is already opened.
- * </p>
- **/
- public void open();
-
- /**
- * <p>
- * This method de-initializes the resource source. It is called when
- * the associated module is removed from the <tt>ModuleManager</tt> or
- * when the module is reset by the <tt>ModuleManager</tt>.
- * </p>
- **/
- public void close();
-
- /**
- * <p>
- * This method returns a boolean indicating whether the resource source
- * contains the specified resource.
- * </p>
- * @param name the name of the resource whose existence is being checked.
- * @param <tt>true</tt> if the resource source has the resource, <tt>false</tt>
- * otherwise.
- * @throws java.lang.IllegalStateException if the resource source has not
- * been opened.
- **/
- public boolean hasResource(String name) throws IllegalStateException;
-
- /**
- * <p>
- * This method returns a byte array of the specified resource's contents.
- * </p>
- * @param name the name of the resource to retrieve.
- * @param a byte array of the resource's contents or <tt>null</tt>
- * if the resource was not found.
- * @throws java.lang.IllegalStateException if the resource source has not
- * been opened.
- **/
- public byte[] getBytes(String name) throws IllegalStateException;
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/SearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/SearchPolicy.java
deleted file mode 100644
index dfa51f2..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/SearchPolicy.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.net.URL;
-
-/**
- * <p>
- * This interface represents a policy to define the most basic behavior
- * of how classes, resources, and native libraries within a specific instance
- * of <tt>ModuleManager</tt> are found. A <tt>ModuleManager</tt> manages a set of
- * <tt>Module</tt>s, each of which is a potential source of classes, resources,
- * and native libraries. The search policy makes it possible to consult these
- * sources without hard-coding assumptions about application behavior
- * or structure. Applicaitons inject their own specific class loading policy
- * by creating a custom search policy or by selecting a pre-existing search
- * policy that matches their needs.
- * </p>
- * <p>
- * The search policy is used by <tt>ModuleClassLoader</tt>, of which, there
- * is one per <tt>Module</tt> within a given <tt>ModuleManager</tt> instance.
- * The search policy is consulted by the <tt>ModuleClassLoader</tt> whenever
- * there is a request for a class, resource, or native library. The search
- * policy will generally search other modules in an application-specific
- * way in order to find the requested item; for example, an application may
- * use a policy where module's may import from one another. If the search
- * policy provides an answer, then the <tt>ModuleClassLoader</tt> will use
- * this to answer the originating request.
- * </p>
- * <p>
- * <b><i>Important:</i></b> The search policy <i>searches</i> modules in
- * some application-specific manner in order to find a class or resource.
- * This <i>search</i> is instigated, either directly or indirectly, by calls
- * to <tt>ModuleClassLoader.loadClass()</tt> and <tt>ModuleClassLoader.getResource()</tt>,
- * respectively. In order for the search policy to load a class or resource,
- * it must <b>not</b> use <tt>ModuleClassLoader.loadClass()</tt> or
- * <tt>ModuleClassLoader.getResource()</tt> again, because this would result
- * in an infinite loop. Instead, the <tt>ModuleClassLoader</tt> offers the
- * the methods <tt>ModuleClassLoader.loadClassFromModule()</tt> and
- * <tt>ModuleClassLoader.getResourceFromModule()</tt> to search a given module
- * and to avoid an infinite loop.
- * </p>
- * <pre>
- * ...
- * public Class findClass(Module module, String name)
- * {
- * Module[] modules = m_mgr.getModules();
- * for (int i = 0; i < modules.length; i++)
- * {
- * try {
- * Class clazz = modules[i].getClassLoader().loadClassFromModule(name);
- * if (clazz != null)
- * {
- * return clazz;
- * }
- * } catch (Throwable th) {
- * }
- * }
- *
- * return null;
- * }
- * ...
- * </pre>
- * <p>
- * In the above code, the search policy "exhaustively" searches every module in the
- * <tt>ModuleManager</tt> to find the requested resource. Note that this policy
- * will also search the module that originated the request, which is not totally
- * necessary since returning <tt>null</tt> will cause the <tt>ModuleClassLoader</tt>
- * to search the originating module's <tt>ResourceSource</tt>s.
- * </p>
-**/
-public interface SearchPolicy
-{
- /**
- * <p>
- * This method is called once by the <tt>ModuleManager</tt> to
- * give the search policy instance a reference to its associated
- * module manager. This method should be implemented such that
- * it cannot be called twice; calling this method a second time
- * should produce an illegal state exception.
- * </p>
- * @param mgr the module manager associated with this search policy.
- * @throws java.lang.IllegalStateException if the method is called
- * more than once.
- **/
- public void setModuleManager(ModuleManager mgr)
- throws IllegalStateException;
-
- /**
- * <p>
- * The <tt>ModuleClassLoader</tt> calls this method before performing
- * the call to <tt>ClassLoader.defineClass()</tt> to give the search policy
- * an opportunity to define the <tt>Package</tt> object for the specified
- * package. The method should return an array of <tt>String</tt> values for
- * each of the following: specTitle, specVersion, specVendor, implTitle,
- * implVersion, and implVendor. See <tt>ClassLoader.definePackage()</tt>
- * for more details. The returned array may contain <tt>null</tt>s, but
- * the return array must have six elements.
- * </p>
- * @param module the module requesting a class from the package.
- * @param pkgName the package name of the class being requested.
- * @return an array containing values for creating the <tt>Package</tt>
- * object for the specified package.
- **/
- public Object[] definePackage(Module module, String pkgName);
-
- /**
- * <p>
- * When a module instigates a class load operation, this method is called
- * to find the desired class for the instigating module. This method is
- * called <b>before</b> searching the module's resource sources for the class.
- * How the class is found is dependent upon the search policy implementation.
- * </p>
- * <p>
- * This method may return <tt>null</tt> or throw an exception if the
- * specified class is not found. Whether a specific search policy
- * implementation should do one or the other depends on the details
- * of the specific search policy. The <tt>ModuleClassLoader</tt>
- * first delegates to this method, then to the local resources
- * sources of the module, and then finally to then the
- * <tt>SearchPolicy.findClassAfterModule()</tt> method. If this method
- * returns null, then the search for the class will continue to these
- * latter two steps. On the other hand, if this method returns a class
- * or throws an exception, then the latter two steps will not be searched.
- * </p>
- * <p>
- * <b>Important:</b> If the implementation of this method delegates
- * the class loading to a <tt>ModuleClassLoader</tt> of another module,
- * then it should <b>not</b> use the method <tt>ModuleClassLoader.loadClass()</tt>
- * to load the class; it should use <tt>ModuleClassLoader.loadClassFromModule()</tt>
- * instead. This is necessary to eliminate an infinite loop that would
- * occur otherwise. Also, with respect to the <tt>ModuleLoader</tt> framework,
- * this method will only be called by a single thread at a time and is only
- * intended to be called by <tt>ModuleClassLoader.loadClass()</tt>.
- * </p>
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the class.
- * @param name the name of the class being loaded.
- * @return the class if found, <tt>null</tt> otherwise.
- * @throws java.lang.ClassNotFoundException if the class could not be
- * found and the entire search operation should fail.
- **/
- public Class findClassBeforeModule(ClassLoader parent, Module module, String name)
- throws ClassNotFoundException;
-
- /**
- * <p>
- * When a module instigates a class load operation, this method is called
- * to find the desired class for the instigating module. This method is
- * called <b>after</b> searching the module's resource sources for the class.
- * How the class is found is dependent upon the search policy implementation.
- * </p>
- * <p>
- * The <tt>ModuleClassLoader</tt> first delegates to the
- * <tt>SearchPolicy.findClassBeforeModule() method, then to the local
- * resources sources of the module, and then finally to this method.
- * This method is the last attempt to find the class and if it fails
- * (by either return <tt>null</tt> or throwing an exception), then the
- * result of the entire class load will fail.
- * </p>
- * <p>
- * <b>Important:</b> If the implementation of this method delegates
- * the class loading to a <tt>ModuleClassLoader</tt> of another module,
- * then it should <b>not</b> use the method <tt>ModuleClassLoader.loadClass()</tt>
- * to load the class; it should use <tt>ModuleClassLoader.loadClassFromModule()</tt>
- * instead. This is necessary to eliminate an infinite loop that would
- * occur otherwise. Also, with respect to the <tt>ModuleLoader</tt> framework,
- * this method will only be called by a single thread at a time and is only
- * intended to be called by <tt>ModuleClassLoader.loadClass()</tt>.
- * </p>
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the class.
- * @param name the name of the class being loaded.
- * @return the class if found, <tt>null</tt> otherwise.
- * @throws java.lang.ClassNotFoundException if the class could not be
- * found and the entire search operation should fail.
- **/
- public Class findClassAfterModule(ClassLoader parent, Module module, String name)
- throws ClassNotFoundException;
-
- /**
- * <p>
- * This method tries to find the specified resource for the specified
- * module. How the resource is found or whether it is actually retrieved
- * from the specified module is dependent upon the implementation. The
- * default <tt>ModuleClassLoader.getResource()</tt> method does not do
- * any searching on its own.
- * </p>
- * <p>
- * This method may return <tt>null</tt> or throw an exception if the
- * specified resource is not found. Whether a specific search policy
- * implementation should do one or the other depends on the details
- * of the specific search policy. The <tt>ModuleClassLoader</tt>
- * first delegates to this method and then to the local resource
- * sources of the module. If this method returns null, then the local
- * resource sources will be searched. On the other hand, if this method
- * throws an exception, then the local resource sources will not be
- * searched.
- * </p>
- * <p>
- * <b>Important:</b> If the implementation of this method delegates
- * the resource loading to a <tt>ModuleClassLoader</tt> of another module,
- * then it should not use the method <tt>ModuleClassLoader.getResource()</tt>
- * to get the resource; it should use <tt>ModuleClassLoader.getResourceFromModule()</tt>
- * instead. This is necessary to eliminate an infinite loop that would
- * occur otherwise. Also, with respect to the <tt>ModuleLoader</tt> framework,
- * this method will only be called by a single thread at a time and is not
- * intended to be called directly.
- * </p>
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the resource.
- * @param name the name of the resource being loaded.
- * @return a <tt>URL</tt> to the resource if found, <tt>null</tt> otherwise.
- * @throws org.apache.felix.moduleloader.ResourceNotFoundException if the
- * resource could not be found and the entire search operation
- * should fail.
- **/
- public URL findResource(ClassLoader parent, Module module, String name)
- throws ResourceNotFoundException;
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/URLPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/URLPolicy.java
deleted file mode 100644
index 452aebc..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/URLPolicy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-import java.net.URL;
-
-/**
- * <p>
- * This interface represents the <tt>ModuleLoader</tt>'s policy for creating
- * <tt>URL</tt> for resource loading and security purposes. Java requires the
- * use of <tt>URL</tt>s for resource loading and security. For resource loading,
- * <tt>URL</tt>s are returned for requested resources. Subsequently, the resource
- * <tt>URL</tt> is used to create an input stream for reading the resources
- * bytes. With respect to security, <tt>URL</tt>s are used when defining a
- * class in order to determine where the code came from, this concept is called
- * a <tt>CodeSource</tt>. This approach enables Java to assign permissions to
- * code that originates from particular locations.
- * </p>
- * <p>
- * The <tt>ModuleManager</tt> requires a concrete implementation of this
- * interface in order to function. Whenever the <tt>ModuleManager</tt> requires
- * a <tt>URL</tt> for either resource loading or security, it delegates to
- * the policy implementation. A default implementation is provided,
- * called <a href="DefaultURLPolicy.html"><tt>DefaultURLPolicy</tt></a>, but
- * it only supports resource loading, not security.
- * </p>
- * @see org.apache.felix.moduleloader.ModuleManager
- * @see org.apache.felix.moduleloader.DefaultURLPolicy
-**/
-public interface URLPolicy
-{
- /**
- * <p>
- * This method should return a <tt>URL</tt> that represents the
- * location from which the module originated. This <tt>URL</tt>
- * can be used when assigning permissions to the module, such as
- * is done in the Java permissions policy file.
- * </p>
- * @param mgr the <tt>ModuleManager</tt> of the module.
- * @param module the module for which the <tt>URL</tt> is to be created.
- * @return an <tt>URL</tt> to associate with the module.
- **/
- public URL createCodeSourceURL(ModuleManager mgr, Module module);
-
- /**
- * <p>
- * This method should return a <tt>URL</tt> that is suitable
- * for accessing the bytes of the specified resource. It must be possible
- * open a connection to this <tt>URL</tt>, which may require that
- * the implementer of this method also introduce a custom
- * <tt>java.net.URLStreamHander</tt> when creating the <tt>URL</tt>.
- * </p>
- * @param mgr the <tt>ModuleManager</tt> of the module.
- * @param module the module for which the resource is being loaded.
- * @param rsIdx the index of the <tt>ResourceSource</tt> containing the resource.
- * @param name the name of the resource being loaded.
- * @return an <tt>URL</tt> for retrieving the resource.
- **/
- public URL createResourceURL(ModuleManager mgr, Module module, int rsIdx, String name);
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/Util.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/Util.java
deleted file mode 100755
index 34b16d7..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/Util.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader;
-
-public class Util
-{
- public static String getClassName(String className)
- {
- if (className == null)
- {
- className = "";
- }
- return (className.lastIndexOf('.') < 0)
- ? "" : className.substring(className.lastIndexOf('.') + 1);
- }
-
- public static String getClassPackage(String className)
- {
- if (className == null)
- {
- className = "";
- }
- return (className.lastIndexOf('.') < 0)
- ? "" : className.substring(0, className.lastIndexOf('.'));
- }
-
- public static String getResourcePackage(String resource)
- {
- if (resource == null)
- {
- resource = "";
- }
- // NOTE: The package of a resource is tricky to determine since
- // resources do not follow the same naming conventions as classes.
- // This code is pessimistic and assumes that the package of a
- // resource is everything up to the last '/' character. By making
- // this choice, it will not be possible to load resources from
- // imports using relative resource names. For example, if a
- // bundle exports "foo" and an importer of "foo" tries to load
- // "/foo/bar/myresource.txt", this will not be found in the exporter
- // because the following algorithm assumes the package name is
- // "foo.bar", not just "foo". This only affects imported resources,
- // local resources will work as expected.
- String pkgName = (resource.startsWith("/")) ? resource.substring(1) : resource;
- pkgName = (pkgName.lastIndexOf('/') < 0)
- ? "" : pkgName.substring(0, pkgName.lastIndexOf('/'));
- pkgName = pkgName.replace('/', '.');
- return pkgName;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/CompatibilityPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/CompatibilityPolicy.java
deleted file mode 100644
index 86b7efd..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/CompatibilityPolicy.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-/**
- * <p>
- * This interface represents the naming and version numbering policy of
- * import and export identifiers for the <tt>ImportSearchPolicy</tt>. A concrete
- * implementation of this interface is required to create an instance
- * of <tt>ImportSearchPolicy</tt>. The sole purpose of this interface
- * is to allow the <tt>ImportSearchPolicy</tt> to determine if one
- * import/export identifier and version is compatible with another.
- * </p>
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy
-**/
-public interface CompatibilityPolicy
-{
- /**
- * Compares two import/export identifiers.
- * @param leftId the identifier to test for compatibility.
- * @param leftVersion the version number to test for compatibility.
- * @param rightId the identifier used as the compatibility base line.
- * @param rightVersion the version used as the compatibility base line.
- * @return <tt>0</tt> if the identifiers are equal, <tt>-1</tt> if the
- * left identifier is less then the right identifier, and <tt>1</tt>
- * if the left identifier is greater than the right identifier.
- * @throws java.lang.IllegalArgumentException if the two identifiers
- * are not comparable, i.e., they refer to intrinsically different
- * entities.
- **/
- public int compare(
- Object leftId, Object leftVersion,
- Object rightId, Object rightVersion);
-
- /**
- * Returns whether the first import/export identifer is compatible
- * with the second; this method should not throw any exceptions.
- * @param leftId the identifier to test for compatibility.
- * @param leftVersion the version number to test for compatibility.
- * @param rightId the identifier used as the compatibility base line.
- * @param rightVersion the version used as the compatibility base line.
- * @return <tt>true</tt> if the left version number object is compatible
- * with the right version number object, otherwise <tt>false</tt>.
- **/
- public boolean isCompatible(
- Object leftId, Object leftVersion,
- Object rightId, Object rightVersion);
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ExhaustiveSearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ExhaustiveSearchPolicy.java
deleted file mode 100644
index d98d8e6..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ExhaustiveSearchPolicy.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-import java.net.URL;
-
-import org.apache.felix.moduleloader.*;
-
-/**
- * <p>
- * This class implements a <tt>ModuleLoader</tt> search policy that
- * exhaustively and linearly searches all modules when trying to load
- * a particular class or resource. As a result of this algorithm, every class loader
- * for every module is essentially identical, meaning that each will
- * load a given class or resource from the same class loader. This search policy
- * provides behavior similar to the standard <tt>CLASSPATH</tt> environment
- * variable approach. The main difference is that modules can be added
- * to the module manager at run time; thus, the class path is dynamically
- * extended. This search policy is not fully dynamic, since it does not
- * support the removal of modules at run time; if a module is removed from
- * the module manager at run time, there is no attempt to clean up its
- * loaded classes.
- * </p>
- * @see org.apache.felix.moduleloader.SearchPolicy
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ModuleClassLoader
- * @see org.apache.felix.moduleloader.ModuleManager
-**/
-public class ExhaustiveSearchPolicy implements SearchPolicy
-{
- private ModuleManager m_mgr = null;
-
- /**
- * This method is part of the <tt>SearchPolicy</tt> interface.
- * This method is called by the <tt>ModuleManager</tt> once to
- * give the search policy instance a reference to its associated
- * module manager. This method should be implemented such that
- * it cannot be called twice; calling this method a second time
- * should produce an illegal state exception.
- * @param mgr the module manager associated with this search policy.
- * @throws java.lang.IllegalStateException if the method is called
- * more than once.
- **/
- public void setModuleManager(ModuleManager mgr)
- throws IllegalStateException
- {
- if (m_mgr == null)
- {
- m_mgr = mgr;
- }
- else
- {
- throw new IllegalStateException("Module manager is already initialized");
- }
- }
-
- public Object[] definePackage(Module module, String pkgName)
- {
- return null;
- }
-
- /**
- * This method finds the specified class for the specified module. It
- * finds the class by linearly asking each module in the module manager
- * for the specific class. As soon as the class is found, it is returned.
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the class.
- * @param name the name of the class being loaded.
- * @return the class if found, <tt>null</tt> otherwise.
- **/
- public Class findClassBeforeModule(ClassLoader parent, Module module, String name)
- {
- // First, try to load from parent.
- if (parent != null)
- {
- try
- {
- Class c = parent.loadClass(name);
- if (c != null)
- {
- return c;
- }
- }
- catch (ClassNotFoundException ex)
- {
- // Ignore and search modules.
- }
- }
-
- Module[] modules = m_mgr.getModules();
- for (int i = 0; i < modules.length; i++)
- {
- try {
- Class clazz = modules[i].getClassLoader().loadClassFromModule(name);
- if (clazz != null)
- {
- return clazz;
- }
- } catch (Throwable th) {
- }
- }
-
- return null;
- }
-
- public Class findClassAfterModule(ClassLoader parent, Module module, String name)
- {
- return null;
- }
-
- /**
- * This method finds the specified resource for the specified module. It
- * finds the resource by linearly asking each module in the module manager
- * for specific resource. As soon as the resource is found, a <tt>URL</tt>
- * to it is returned.
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the resource.
- * @param name the name of the resource being loaded.
- * @return a <tt>URL</tt> to the resource if found, <tt>null</tt> otherwise.
- **/
- public URL findResource(ClassLoader parent, Module module, String name)
- {
- // First, try to load from parent.
- if (parent != null)
- {
- URL url = parent.getResource(name);
- if (url != null)
- {
- return url;
- }
- }
-
- Module[] modules = m_mgr.getModules();
- for (int i = 0; i < modules.length; i++)
- {
- try {
- URL url = modules[i].getClassLoader().getResourceFromModule(name);
- if (url != null)
- {
- return url;
- }
- } catch (Throwable th) {
- }
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ImportSearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ImportSearchPolicy.java
deleted file mode 100644
index 3fefc24..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ImportSearchPolicy.java
+++ /dev/null
@@ -1,1322 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-import java.net.URL;
-import java.util.*;
-
-import org.apache.felix.moduleloader.*;
-
-/**
- * <p>
- * This class implements a <tt>ModuleLoader</tt> search policy to support
- * modules that import and export classes and resources from/to one another.
- * Modules import from other modules by specifying a set of import identifiers
- * and associated version numbers. Modules export their classes and
- * resources by specifying a set of export identifiers and associated
- * versions. Exports for a given module are also treated as imports for that module,
- * meaning that it is possible for a module that exports classes to not use
- * the classes it exports, but to actually use classes that are exported from
- * another module. This search policy requires the following meta-data
- * attributes be attached to each module:
- * </p>
- * <ul>
- * <li><tt>ImportSearchPolicy.EXPORTS_ATTR</tt> - the "<tt>exports</tt>"
- * meta-data attribute is used to declare the module's exports,
- * </li>
- * <li><tt>ImportSearchPolicy.IMPORTS_ATTR</tt> - the "<tt>imports</tt>"
- * meta-data attribute is used to declare the module's imports,
- * </li>
- * <li><tt>ImportSearchPolicy.PROPAGATES_ATTR</tt> - the "<tt>propagates</tt>"
- * meta-data attribute is used to declare which imports are exposed or
- * "propagated" to clients of the module's exports, and
- * </li>
- * <li><tt>ImportSearchPolicy.VALID_ATTR</tt> - the "<tt>valid</tt>"
- * meta-data attribute signifies the current <i>validation</i> status
- * of the module (this will be defined more fully below).
- * </li>
- * </ul>
- * <p>
- * The value of the <tt>ImportSearchPolicy.EXPORTS_ATTR</tt> attribute is
- * an array of <tt>Object</tt> arrays, i.e., <tt>Object[][]</tt>. Each element
- * in the array signifies a particular export that is offered by this
- * associated module. Each element is an array triple of
- * <tt>Object</tt>, where the index into this triple is:
- * </p>
- * <ul>
- * <li><tt>ImportSearchPolicy.IDENTIFIER_IDX</tt> - the first element
- * is the export identifier object, used to identify the
- * export target. The export identifier does not have any special
- * meaning to the search policy and any value is allowed. A
- * typical identifier might be the package name of the exported classes,
- * such as <tt>javax.servlet</tt>.
- * </li>
- * <li><tt>ImportSearchPolicy.VERSION_IDX</tt> - the second element
- * is the export version number. The version number does not have
- * any special meaning to the search policy and any value is allowed.
- * A typical version number might be major, minor, and release number.
- * </li>
- * <li><tt>ImportSearchPolicy.RESOLVING_MODULE_IDX</tt> - the third element
- * is the resolving module for this export; since exports are treated like
- * imports, it is possible that the resolving module will not be the
- * exporting module itself. This value is filled in automatically by the
- * search policy and is initially <tt>null</tt>.
- * </li>
- * </ul>
- * </p>
- * <p>
- * The value of the <tt>ImportSearchPolicy.IMPORTS_ATTR</tt> attribute is
- * essentially the same as the <tt>ImportSearchPolicy.EXPORTS_ATTR</tt> defined
- * above; the only difference is that the array of versioned identifiers denote
- * import targets rather than exports.
- * </p>
- * <p>
- * The value of the <tt>ImportSearchPolicy.PROPAGATES_ATTR</tt> attribute is
- * an array of <tt>Object</tt>s, i.e., <tt>Object[]</tt>. Each element in the
- * array is an identifier of a propagated import target from the
- * <tt>ImportSearchPolicy.IMPORTS_ATTR</tt> attribute. Only identifiers for
- * import targets are candidates for inclusion and the version number is
- * unnecessary since it is assumed from the corresponding import target.
- * </p>
- * <p>
- * The value of the <tt>ImportSearchPolicy.VALID_ATTR</tt> attribute is a
- * <tt>Boolean</tt>. The value is initially set to <tt>Boolean.FALSE</tt>
- * and indicates that the module has not yet been validated. After the module
- * is validated, the value is set to <tt>Boolean.TRUE</tt>. The search policy
- * automatically adds this attribute to all modules and maintains its value.
- * </p>
- * <p>
- * These meta-data attributes help the search policy enforce consistency
- * using a process called <i>validation</i>; validation ensures that classes
- * and resources are only loaded from a module whose imports are satisfied.
- * Therefore, a <i>valid</i> module is a module whose imports are satisfied and
- * an <i>invalid</i> module is a module whose imports are not yet satisfied.
- * An invalid module may be invalid for two reasons:
- * </p>
- * <p>
- * <ol>
- * <li>Its imports are not available or</li>
- * <li>It has not yet been validated.</li>
- * </ol>
- * </p>
- * <p>
- * These two possibilities arise due to the fact that module validation
- * is not performed until it is necessary (i.e., lazy evaluation). A module
- * is automatically validated when an attempt is made to get classes or
- * resources from it, although it is possible to manually validate a module.
- * For a given module, called <tt>M</tt>, the validation process attempts to
- * find an exporting module for every import target of <tt>M</tt>. If an
- * exporter is not found for a specific import target, then the validation of
- * module <tt>M</tt> fails. If an exporting module is found, then this module
- * is also validated, if it is not already. As a result, the validation of
- * module <tt>M</tt> depends on the validation of the transitive closure of
- * all modules on which <tt>M</tt> depends. It is also possible for modules
- * to exhibit dependency cycles; circular dependencies are allowed.
- * Initially, a module's <tt>VALID_ATTR</tt> is set to <tt>Boolean.FALSE</tt>,
- * but after the module is successfully validated, this attribute is set to
- * <tt>Boolean.TRUE</tt>.
- * </p>
- * <p>
- * Besides ensuring that every import target is resolved to an appropriate
- * exporting module, the validation process also attempts to maintain
- * consistency along "propagation" chains. Propagation occurs when a module
- * imports classes that are also visible from its own exports; for example,
- * an HTTP server implementation may import classes from <tt>javax.servlet</tt>
- * and export classes that have methods that use the type <tt>javax.servlet.Servlet</tt>
- * in their signatures. Monitoring these types of occurences is important
- * to uncover import source and version conflicts when multiple sources or
- * versions of an import target are available within one virtual machine. When
- * a module <tt>M</tt> is validated, the propagation information of each
- * module that resolves the imports of <tt>M</tt> is checked to ensure
- * that they do not propagate conflicting sources of <tt>M</tt>'s
- * imports; specifically, it is verified that all propagators of a
- * particular import target have the same source module for that import
- * target.
- * </p>
- * <p>
- * To facilitate applicability in as many scenarios as possible, this search
- * policy delegates some decisions via additional policy interfaces. The following
- * two policy interfaces must be specified by the code that instantiates the
- * <tt>ImportSearchPolicy</tt> object:
- * </p>
- * <ul>
- * <li><tt>CompatibilityPolicy</tt> - this policy is used to determine
- * whether import/export version numbers are compatible.
- * </li>
- * <li><tt>SelectionPolicy</tt> - this policy is used to resolve a specific
- * import target when multiple candidate exporting modules exist.
- * </li>
- * </ul>
- * <p>
- * Once an instance is created with definitions of the above policy interfaces,
- * this search policy will operate largely self-contained. There are a few utility
- * methods for manually validating modules, adding validation listeners, and
- * access meta-data attributes, but for the most part these are not necessary
- * except for implementing more sophisticated infrastructure.
- * </p>
- * <p>
- * The follow snippet of code illustrates a typical usage scenario for
- * this search policy:
- * </p>
- * <pre>
- * ...
- * ImportSearchPolicy searchPolicy =
- * new ImportSearchPolicy(
- * new MyCompatibilityPolicy(), new MySelectionPolicy());
- * ModuleManager mgr = new ModuleManager(searchPolicy);
- * ...
- * Object[][] exports = new Object[][] {
- * { "org.apache.jasper", "2.1.0", null }
- * };
- * Object[][] imports = new Object[][] {
- * { "javax.servlet", "2.3.1", null }
- * };
- * Object[][] attributes = new Object[][] {
- * new Object[] { ImportSearchPolicy.EXPORTS_ATTR, exports },
- * new Object[] { ImportSearchPolicy.IMPORTS_ATTR, imports },
- * new Object[] { ImportSearchPolicy.PROPAGATES_ATTR, new Object[] { "javax.servlet" } }
- * };
- * ResourceSource[] resSources = new ResourceSource[] {
- * new JarResourceSource(file1)
- * new JarResourceSource(file2)
- * };
- * Module module = mgr.addModule(id, attributes, resSources, null);
- * ClassLoader loader = module.getClassLoader();
- * // Assuming that all imports are satisfied...
- * Class clazz = loader.loadClass("org.foo.MyClass");
- * ...
- * </pre>
- * <p>
- * The above code snippet illustrates creating a module with one export and one
- * import, where the import is also propagated via the module's export. The module
- * has multiple resource sources, but no library sources.
- * </p>
- * @see org.apache.felix.moduleloader.SearchPolicy
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ModuleClassLoader
- * @see org.apache.felix.moduleloader.ModuleManager
-**/
-public class ImportSearchPolicy implements SearchPolicy, ModuleListener
-{
- /**
- * This is the name of the "exports" meta-data attribute that
- * should be attached to each module. The value of this attribute
- * is of type <tt>Object[][]</tt> and is described in the overview
- * documentation for this class.
- **/
- public static final String EXPORTS_ATTR = "exports";
- /**
- * This is the name of the "imports" meta-data attribute that
- * should be attached to each module. The value of this attribute
- * is of type <tt>Object[][]</tt> and is described in the overview
- * documentation for this class.
- **/
- public static final String IMPORTS_ATTR = "imports";
- /**
- * This is the name of the "propagates" meta-data attribute that
- * should be attached to each module. The value of this attribute
- * is of type <tt>Object[]</tt> and is described in the overview
- * documentation for this class.
- **/
- public static final String PROPAGATES_ATTR = "propagates";
- /**
- * This is the name of the "valid" meta-data attribute that is
- * automatically attached to each module. The value of this attribute
- * is of type <tt>Boolean</tt> and is described in the overview
- * documentation for this class.
- **/
- public static final String VALID_ATTR = "valid";
-
- /**
- * This is the index used to retrieve the import or export identifier
- * from a given element of the <tt>EXPORTS_ATTR</tt> or the <tt>IMPORTS_ATTR</tt>
- * attribute.
- **/
- public static final int IDENTIFIER_IDX = 0;
- /**
- * This is the index used to retrieve the import or export version number
- * from a given element of the <tt>EXPORTS_ATTR</tt> or the <tt>IMPORTS_ATTR</tt>
- * attribute.
- **/
- public static final int VERSION_IDX = 1;
- /**
- * This is the index used to retrieve the resolving module for an import
- * or export target from a given element of the <tt>EXPORTS_ATTR</tt> or
- * the <tt>IMPORTS_ATTR</tt> attribute.
- **/
- public static final int RESOLVING_MODULE_IDX = 2;
-
- private ModuleManager m_mgr = null;
- private CompatibilityPolicy m_compatPolicy = null;
- private SelectionPolicy m_selectPolicy = null;
- private ValidationListener[] m_listeners = null;
- private String[] m_searchAttrs = { IMPORTS_ATTR, EXPORTS_ATTR };
- private static final ValidationListener[] m_noListeners = new ValidationListener[0];
-
- /**
- * Constructs an import search policy instance with the supplied
- * compatibility and selection policies.
- * @param compatPolicy the compatibility policy implementation to be used
- * by the search policy.
- * @param selectPolicy the selection policy implementation to be used
- * by the search policy.
- **/
- public ImportSearchPolicy(
- CompatibilityPolicy compatPolicy,
- SelectionPolicy selectPolicy)
- {
- m_compatPolicy = compatPolicy;
- m_selectPolicy = selectPolicy;
- m_listeners = m_noListeners;
- }
-
- /**
- * Returns the compatibility policy used by this import search policy instance.
- * @return the compatibility policy of this import search policy instance.
- **/
- public CompatibilityPolicy getCompatibilityPolicy()
- {
- return m_compatPolicy;
- }
-
- /**
- * Returns the selection policy used by this import search policy instance.
- * @return the selection policy of this import search policy instance.
- **/
- public SelectionPolicy getSelectionPolicy()
- {
- return m_selectPolicy;
- }
-
- // JavaDoc comment copied from SearchPolicy.
- public void setModuleManager(ModuleManager mgr)
- throws IllegalStateException
- {
- if (m_mgr == null)
- {
- m_mgr = mgr;
- m_mgr.addModuleListener(this);
- }
- else
- {
- throw new IllegalStateException("Module manager is already initialized");
- }
- }
-
- public Object[] definePackage(Module module, String pkgName)
- {
- return null;
- }
-
- /**
- * This method is part of the <tt>SearchPolicy</tt> interface; it
- * should not be called directly. This method finds a class
- * based on the import/export meta-data attached to the module.
- * It first attempts to validate the target module, if it cannot
- * be validated, then a <tt>ClassNotFoundException</tt> is thrown.
- * Once the module is validated, the module's imports are searched
- * for the target class, then the module's exports are searched.
- * If the class is found in either place, then it is returned;
- * otherwise, <tt>null</tt> is returned.
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the class.
- * @param name the name of the class being loaded.
- * @return the class if found, <tt>null</tt> otherwise.
- * @throws java.lang.ClassNotFoundException if the target module
- * could not be validated.
- **/
- public Class findClassBeforeModule(ClassLoader parent, Module module, String name)
- throws ClassNotFoundException
- {
- // First, try to validate the originating module.
- try {
- validate(module);
- } catch (ValidationException ex) {
- throw new ClassNotFoundException(name);
- }
-
- // Try to load from parent.
- if (parent != null)
- {
- try
- {
- Class c = parent.loadClass(name);
- if (c != null)
- {
- return c;
- }
- }
- catch (ClassNotFoundException ex)
- {
- // Ignore and search imports/exports.
- }
- }
-
- // Get the package of the target class.
- String pkgName = Util.getClassPackage(name);
-
- // We delegate to the module's imports for finding the
- // desired class first, then we delegate to the module's
- // exports for finding the desired class. We do this because
- // implicitly a module imports everything that it exports.
- // To avoid code duplication, we use a simple array of
- // attribute names to loop through both of the imports
- // and exports meta-data searching for the desired class.
- for (int attrIdx = 0; attrIdx < m_searchAttrs.length; attrIdx++)
- {
- Object[][] imports = getImportsOrExports(module, m_searchAttrs[attrIdx]);
-
- // If the module doesn't import anything, then just
- // return null.
- if ((imports != null) && (imports.length > 0))
- {
- for (int i = 0; i < imports.length; i++)
- {
- // Only check when the package of the class is
- // the same as the import package.
- if (imports[i][IDENTIFIER_IDX].equals(pkgName))
- {
- Module resolvingModule = (Module) imports[i][RESOLVING_MODULE_IDX];
- try {
- Class clazz =
- resolvingModule.getClassLoader().loadClassFromModule(name);
- if (clazz != null)
- {
- return clazz;
- }
- } catch (Throwable th) {
- // Not much we can do.
- System.err.println("ImportSearchPolicy: " + th.getMessage());
- }
- }
- }
- }
- }
-
- return null;
- }
-
- public Class findClassAfterModule(ClassLoader parent, Module module, String name)
- {
- return null;
- }
-
- /**
- * This method is part of the <tt>SearchPolicy</tt> interface; it
- * should not be called directly. This method finds a resource
- * based on the import/export meta-data attached to the module.
- * It first attempts to validate the target module, if it cannot
- * be validated, then it returns <tt>null</tt>. Once the module is
- * validated, the module's imports are searched for the target
- * resource, then the module's exports are searched. If the resource
- * is found in either place, then a <tt>URL</tt> to is is returned;
- * otherwise, <tt>null</tt> is returned.
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the resource.
- * @param name the name of the resource being loaded.
- * @return a <tt>URL</tt> to the resource if found, <tt>null</tt> otherwise.
- **/
- public URL findResource(ClassLoader parent, Module module, String name)
- {
- // First, try to validate the originating module.
- try
- {
- validate(module);
- }
- catch (ValidationException ex)
- {
- return null;
- }
-
- // Try to load from parent.
- if (parent != null)
- {
- URL url = parent.getResource(name);
- if (url != null)
- {
- return url;
- }
- }
-
- // Get the package of the target resource.
- String pkgName = Util.getResourcePackage(name);
-
- // We delegate to the module's imports for finding the
- // desired class first, then we delegate to the module's
- // exports for finding the desired class. We do this because
- // implicitly a module imports everything that it exports.
- // To avoid code duplication, we use a simple array of
- // attribute names to loop through both of the imports
- // and exports meta-data searching for the desired class.
- for (int attrIdx = 0; attrIdx < m_searchAttrs.length; attrIdx++)
- {
- Object[][] imports = getImportsOrExports(module, m_searchAttrs[attrIdx]);
-
- // If the module doesn't import or export anything,
- // then just return null.
- if ((imports != null) && (imports.length > 0))
- {
- for (int i = 0; i < imports.length; i++)
- {
- // Only check when the package of the resource is
- // the same as the import package.
- if (imports[i][IDENTIFIER_IDX].equals(pkgName))
- {
- Module resolvingModule = (Module) imports[i][RESOLVING_MODULE_IDX];
- try {
- URL url =
- resolvingModule.getClassLoader().getResourceFromModule(name);
- if (url != null)
- {
- return url;
- }
- } catch (Throwable th) {
- }
- }
- }
- }
- }
-
- return null;
- }
-
- private Map m_validateMap = new HashMap();
- private Module m_rootModule = null;
-
- /**
- * This method validates the specified target module. If the module
- * is already validated, then this method returns immediately. This
- * method synchronizes on the associated module manager to ensure that
- * modules are not added or removed while the validation is occuring.
- * Each import and export for the target module are resolved by first
- * using the compatibility policy to create a list of candidate export
- * modules, then using the selection policy to choose among the
- * candidates. Each selected candidate is also recursively validated;
- * this process validates a transitive closure of all dependent modules.
- * After the selected candidate is validated, its propagated imports
- * are checked to make sure that they do not conflict with any existing
- * propagated imports. If no validation errors occur, then all dependent
- * modules are marked as validated, if they are not already validated.
- * If an error occurs, the valid state of all modules remains unchanged.
- * @param module the module to validate.
- * @throws org.apache.felix.moduleloader.search.ValidationException if
- * the module or any dependent modules could not be validated.
- **/
- public void validate(Module module)
- throws ValidationException
- {
- if (getValidAttribute(module).booleanValue())
- {
- return;
- }
-
- // Flag to indicate whether the bundle is valid or not.
- boolean isValid = true;
-
- // This list will be used to remember which bundles
- // were validated so that the validation events can
- // be fired outside of the synchronized block.
- List fireValidatedList = null;
-
- // Will hold the exception to be thrown or rethrown.
- ValidationException invalidException = null;
-
- // Synchronize on the module manager, because we don't want
- // anything to change while we are in the middle of this
- // operation.
- synchronized (m_mgr)
- {
- // If we are already validating this module, then
- // just return; this is necessary for cycles.
- if (m_validateMap.get(module) != null)
- {
- return;
- }
-
- // Add the module to the validation map; this
- // is necessary for cycles.
- m_validateMap.put(module, module);
-
- // Keep track of the root module that started
- // the validation request; this is necessary
- // for cycles.
- if (m_rootModule == null)
- {
- m_rootModule = module;
- }
-
- // Now perform the validation algorithm.
- Map propagateMap = new HashMap();
-
- // Validation binds the module's imports to a specific exporting
- // module. A module also implicitly imports whatever it exports,
- // so exports are validated in the same fashion as imports. It
- // is possible, given the selection policy that a given export
- // may actually be satisfied by a different module (i.e., a
- // module is not guaranteed to be bound to what it exports). Since
- // the imports and exports meta-data are validated in the same
- // fashion, we will use the follow attribute array to loop and
- // validate both imports and exports using the same code.
- for (int attrIdx = 0; (isValid) && (attrIdx < m_searchAttrs.length); attrIdx++)
- {
- // Get the imports (exports are treated as imports to)
- // for the current module.
- Object[][] imports = getImportsOrExports(module, m_searchAttrs[attrIdx]);
- // See if each import has available exporters.
- for (int impIdx = 0; impIdx < imports.length; impIdx++)
- {
- // Get all exporter candidates.
- Module[] candidates =
- getCompatibleModules(
- imports[impIdx][IDENTIFIER_IDX], imports[impIdx][VERSION_IDX]);
- // If there are no candidates, then prepare a
- // validation exception.
- if (candidates == null)
- {
- isValid = false;
- invalidException =
- new ValidationException(
- "Unable to validate module",
- module,
- imports[impIdx][IDENTIFIER_IDX],
- imports[impIdx][VERSION_IDX],
- false);
- break;
- }
-
- // Use selection policy to choose a single export candidate.
- Module exportingModule = m_selectPolicy.select(
- module, imports[impIdx][IDENTIFIER_IDX],
- imports[impIdx][VERSION_IDX], candidates, m_compatPolicy);
- // If there is no export module chosen, then prepare
- // a validation exception.
- if (exportingModule == null)
- {
- isValid = false;
- invalidException =
- new ValidationException(
- "Unable to validate module",
- module,
- imports[impIdx][IDENTIFIER_IDX],
- imports[impIdx][VERSION_IDX],
- false);
- break;
- }
-
- // Make sure that the export module is
- // also validated.
- try
- {
- validate(exportingModule);
- }
- catch (ValidationException ex)
- {
- // Prepare to rethrow the exception if
- // the exporter could not be validated.
- isValid = false;
- invalidException = ex;
- break;
- }
-
- // Keep track of all propagations from each module that this
- // module imports from. Verify that any given import always
- // comes form the same export module, otherwise there will be
- // class cast exceptions.
- Object[] propagates = getPropagatesAttribute(exportingModule);
- for (int propIdx = 0; propIdx < propagates.length; propIdx++)
- {
- // If the module does not import the propagated target,
- // then it can be safely ignored.
- if (doesImport(module, propagates[propIdx]))
- {
- Module sourceModule =
- (Module) propagateMap.get(propagates[propIdx]);
-
- // If the propagation source module has not already been
- // found, then remember the resolving module of the
- // exporting module as the source of the propagated
- // target.
- if (sourceModule == null)
- {
- propagateMap.put(
- propagates[propIdx],
- getImportResolvingModule(
- exportingModule, propagates[propIdx]));
- }
- // If the propagation source module is found, then check to
- // see if it is propagating the import target from the same
- // module as previously determined for this module. If not,
- // then this is a propagation conflict.
- else if (sourceModule !=
- getImportResolvingModule(
- exportingModule, propagates[propIdx]))
- {
- isValid = false;
- invalidException =
- new ValidationException(
- "Unable to validate module",
- exportingModule,
- propagates[propIdx],
- null,
- true);
- break;
- }
- }
- }
-
- // Set the chosen exporting module for the module
- // being validated.
- imports[impIdx][RESOLVING_MODULE_IDX] = exportingModule;
- }
- }
-
- // Since this method is recursive, check to see it we are
- // back at the root module that started the request, which
- // would indicate that the request is finished.
- if (m_rootModule == module)
- {
- // If the result is valid, then we have validated successfully.
- if (isValid)
- {
- // Loop through all modules in validate map
- // and mark them as valid.
- Iterator iter = m_validateMap.keySet().iterator();
- while (iter.hasNext())
- {
- Module m = (Module) iter.next();
- if (!getValidAttribute(m).booleanValue())
- {
- m.setAttribute(VALID_ATTR, Boolean.TRUE);
- if (fireValidatedList == null)
- {
- fireValidatedList = new ArrayList();
- }
- fireValidatedList.add(m);
- }
- }
- }
- // If we are here, then the validate failed, so we
- // need to reset any partially validated modules.
- else
- {
- Iterator iter = m_validateMap.keySet().iterator();
- while (iter.hasNext())
- {
- Module m = (Module) iter.next();
- invalidate(
- m,
- m.getAttributes(),
- m.getResourceSources(),
- m.getLibrarySources());
- }
- }
-
- // Clear the root module and validation map
- // before leaving the synchronized block.
- m_rootModule = null;
- m_validateMap.clear();
- }
- }
-
- // (Re)throw the exception if invalid, otherwise
- // fire validation events if the validated event
- // list is not null.
- if (!isValid)
- {
- throw invalidException;
- }
- else if (fireValidatedList != null)
- {
- for (int i = 0; i < fireValidatedList.size(); i++)
- {
- fireModuleValidated((Module) fireValidatedList.get(i));
- }
- }
- }
-
- /**
- * This method returns a list of modules that have an export
- * that is compatible with the given import identifier and version.
- * @param identifier the import identifier.
- * @param version the version of the import identifier.
- * @return an array of modules that have compatible exports or <tt>null</tt>
- * if none are found.
- **/
- protected Module[] getCompatibleModules(Object identifier, Object version)
- {
- List list = null;
- Module[] modules = m_mgr.getModules();
- for (int modIdx = 0; modIdx < modules.length; modIdx++)
- {
- Object[][] exports = getExportsAttribute(modules[modIdx]);
- for (int expIdx = 0; expIdx < exports.length; expIdx++)
- {
- // If the identifiers are comparable and compatible,
- // then add the export identifier to the list.
- if (m_compatPolicy.isCompatible(
- exports[expIdx][IDENTIFIER_IDX], exports[expIdx][VERSION_IDX],
- identifier, version))
- {
- if (list == null)
- {
- list = new ArrayList();
- }
- list.add(modules[modIdx]);
- }
- }
- }
-
- if (list == null)
- {
- return null;
- }
-
- Module[] result = new Module[list.size()];
- return (Module[]) list.toArray(result);
- }
-
- /**
- * Invalidates a module by flushing its class loader and
- * re-initializing its meta-data values.
- * @param module the module to be invalidated.
- * @param attributes the attributes associated with the module, since they
- * might have changed.
- * @param resSources the resource sources associated wih the module, since they
- * might have changed.
- * @param libSources the library sources associated wih the module, since they
- * might have changed.
- **/
- public void invalidate(
- Module module, Object[][] attributes,
- ResourceSource[] resSources, LibrarySource[] libSources)
- {
- // Synchronize on the module manager, because we don't want
- // anything to change while we are in the middle of this
- // operation.
- synchronized (m_mgr)
- {
- m_mgr.resetModule(module, attributes, resSources, libSources);
- }
-
- // Fire invalidation event if necessary.
- fireModuleInvalidated(m_mgr.getModule(module.getId()));
- }
-
- //
- // Event handling methods for validation events.
- //
-
- /**
- * Adds a validation listener to this import search policy. Validation
- * listeners are notified when a module is validated and/or invalidated
- * by the search policy.
- * @param l the validation listener to add.
- **/
- public void addValidationListener(ValidationListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
-
- // Use the m_noListeners object as a lock.
- synchronized (m_noListeners)
- {
- // If we have no listeners, then just add the new listener.
- if (m_listeners == m_noListeners)
- {
- m_listeners = new ValidationListener[] { l };
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- ValidationListener[] newList = new ValidationListener[m_listeners.length + 1];
- System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
- newList[m_listeners.length] = l;
- m_listeners = newList;
- }
- }
- }
-
- /**
- * Removes a validation listener to this import search policy.
- * @param l the validation listener to remove.
- **/
- public void removeValidationListener(ValidationListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
-
- // Use the m_noListeners object as a lock.
- synchronized (m_noListeners)
- {
- // Try to find the instance in our list.
- int idx = -1;
- for (int i = 0; i < m_listeners.length; i++)
- {
- if (m_listeners[i].equals(l))
- {
- idx = i;
- break;
- }
- }
-
- // If we have the instance, then remove it.
- if (idx >= 0)
- {
- // If this is the last listener, then point to empty list.
- if (m_listeners.length == 1)
- {
- m_listeners = m_noListeners;
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- ValidationListener[] newList = new ValidationListener[m_listeners.length - 1];
- System.arraycopy(m_listeners, 0, newList, 0, idx);
- if (idx < newList.length)
- {
- System.arraycopy(m_listeners, idx + 1, newList, idx,
- newList.length - idx);
- }
- m_listeners = newList;
- }
- }
- }
- }
-
- /**
- * Fires a validation event for the specified module.
- * @param module the module that was validated.
- **/
- protected void fireModuleValidated(Module module)
- {
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ValidationListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(m_mgr, module);
- }
- listeners[i].moduleValidated(event);
- }
- }
-
- /**
- * Fires an invalidation event for the specified module.
- * @param module the module that was invalidated.
- **/
- protected void fireModuleInvalidated(Module module)
- {
- // Event holder.
- ModuleEvent event = null;
-
- // Get a copy of the listener array, which is guaranteed
- // to not be null.
- ValidationListener[] listeners = m_listeners;
-
- // Loop through listeners and fire events.
- for (int i = 0; i < listeners.length; i++)
- {
- // Lazily create event.
- if (event == null)
- {
- event = new ModuleEvent(m_mgr, module);
- }
- listeners[i].moduleInvalidated(event);
- }
- }
-
- //
- // ModuleListener methods.
- //
-
- /**
- * Callback method for <tt>ModuleListener</tt>; this should not
- * be called directly. This callback is used to initialize module
- * meta-data attributes; it adds the <tt>VALID_ATTR</tt> attribute
- * and initializes the resolving module entries in <tt>EXPORTS_ATTR</tt>
- * and <tt>IMPORTS_ATTR</tt> to <tt>null</tt>.
- **/
- public void moduleAdded(ModuleEvent event)
- {
- synchronized (event.getModule())
- {
- // Add valid attribute to all modules.
- event.getModule().setAttribute(VALID_ATTR, Boolean.FALSE);
-
- for (int attrIdx = 0; attrIdx < m_searchAttrs.length; attrIdx++)
- {
- Object[][] imports =
- getImportsOrExports(event.getModule(), m_searchAttrs[attrIdx]);
- for (int i = 0; i < imports.length; i++)
- {
- imports[i][RESOLVING_MODULE_IDX] = null;
- }
- }
- }
- }
-
- /**
- * Callback method for <tt>ModuleListener</tt>; this should not
- * be called directly. This callback is used to re-initialize module
- * meta-data attributes; it adds the <tt>VALID_ATTR</tt> attribute
- * and initializes the resolving module entries in <tt>EXPORTS_ATTR</tt>
- * and <tt>IMPORTS_ATTR</tt> to <tt>null</tt>. It then invalidates
- * all modules that import from the reset module.
- **/
- public void moduleReset(ModuleEvent event)
- {
- // This will reset module meta-data.
- moduleAdded(event);
-
-// TODO: Synchronization?
- ModuleManager m_mgr = (ModuleManager) event.getSource();
- List list = createImporterList(m_mgr, event.getModule());
- for (int i = 0; (list != null) && (i < list.size()); i++)
- {
- Module module = (Module) list.get(i);
- invalidate(
- module, module.getAttributes(),
- module.getResourceSources(), module.getLibrarySources());
- }
- }
-
- /**
- * Callback method for <tt>ModuleListener</tt>; this should not
- * be called directly. Used to listen for module removal events
- * in order to invalidate all the modules that import form the
- * removed moduled.
- **/
- public void moduleRemoved(ModuleEvent event)
- {
-// TODO: Synchronization?
- ModuleManager m_mgr = (ModuleManager) event.getSource();
- List list = createImporterList(m_mgr, event.getModule());
- for (int i = 0; (list != null) && (i < list.size()); i++)
- {
- Module module = (Module) list.get(i);
- invalidate(
- module, module.getAttributes(),
- module.getResourceSources(), module.getLibrarySources());
- }
- }
-
- //
- // Instance utility methods.
- //
-
- /**
- * This utility method returns the module that exports the
- * specified import identifier and version. This method uses the
- * <tt>validate()</tt> method to find the exporting module and,
- * as a result, relies on the compatibility and selection
- * policies associated with this <tt>ImportSearchPolicy</tt>
- * instance. If successful, the returned module is guaranteed
- * to be validated. This method only needs to be used for more
- * advanced purposes (i.e., check import availability dynamically,
- * etc.) and need not be used under normal circumstances.
- * @param identifier the identifier of the import to resolve.
- * @param version the version of the import to resolve.
- * @return the exporting module selected to resolve the specified
- * import target.
- **/
- public Module resolveImportTarget(Object identifier, Object version)
- {
- // Create a fake module that imports the specified target
- // and then try to validate it so we can get the exporting
- // module that is used to satisfy the import.
- Object[] targetImport = { identifier, version, null };
- Object[][] attrs = new Object[][] {
- new Object[] { EXPORTS_ATTR, new Object[0][0] },
- new Object[] { IMPORTS_ATTR, new Object[][] { targetImport } },
- new Object[] { PROPAGATES_ATTR, new Object[0] },
- new Object[] { VALID_ATTR, Boolean.FALSE}
- };
- Module fake = new Module(m_mgr, "resolve import", attrs, null, null, false);
- try {
- validate(fake);
- } catch (ValidationException ex) {
- // Ignore this.
- }
- return (Module) targetImport[RESOLVING_MODULE_IDX];
- }
-
- //
- // Static utility methods.
- //
-
- private static final Object[][] m_emptyImports = new Object[0][0];
- private static final Object[] m_emptyProp = new Object[0];
-
- /**
- * Utility method that returns the <tt>VALID_ATTR</tt> attribute for
- * the specified module.
- * @param module the module whose <tt>VALID_ATTR</tt> attribute is to
- * be retrieved.
- * @return an instance of <tt>Boolean</tt>.
- **/
- public static Boolean getValidAttribute(Module module)
- {
- Object value = module.getAttribute(VALID_ATTR);
- if (value != null)
- {
- return (Boolean) value;
- }
- return Boolean.FALSE;
- }
-
- /**
- * Utility method that returns the <tt>IMPORTS_ATTR</tt> attribute for
- * the specified module.
- * @param module the module whose <tt>IMPORTS_ATTR</tt> attribute is to
- * be retrieved.
- * @return an <tt>Object[][]</tt> value or <tt>null</tt>.
- **/
- public static Object[][] getImportsAttribute(Module module)
- {
- Object value = module.getAttribute(IMPORTS_ATTR);
- if (value != null)
- {
- return (Object[][]) value;
- }
- return m_emptyImports;
- }
-
- /**
- * Utility method that returns the <tt>EXPORTS_ATTR</tt> attribute for
- * the specified module.
- * @param module the module whose <tt>EXPORTS_ATTR</tt> attribute is to
- * be retrieved.
- * @return an <tt>Object[][]</tt> value or <tt>null</tt>.
- **/
- public static Object[][] getExportsAttribute(Module module)
- {
- Object value = module.getAttribute(EXPORTS_ATTR);
- if (value != null)
- {
- return (Object[][]) value;
- }
- return m_emptyImports;
- }
-
- /**
- * Utility method that returns the <tt>IMPORTS_ATTR</tt> or the
- * <tt>EXPORTS_ATTR</tt> attribute for the specified module.
- * @param module the module whose <tt>IMPORTS_ATTR</tt> or
- * <tt>EXPORTS_ATTR</tt> attribute is to be retrieved.
- * @param name either <tt>IMPORTS_ATTR</tt> or <tt>EXPORTS_ATTR</tt>
- * depending on which attribute should be retrieved.
- * @return an <tt>Object[][]</tt> value or <tt>null</tt>.
- **/
- public static Object[][] getImportsOrExports(Module module, String name)
- {
- Object value = module.getAttribute(name);
- if (value != null)
- {
- return (Object[][]) value;
- }
- return m_emptyImports;
- }
-
- /**
- * Utility method that returns the <tt>PROPAGATES_ATTR</tt> attribute for
- * the specified module.
- * @param module the module whose <tt>PROPAGATES_ATTR</tt> attribute is to
- * be retrieved.
- * @return an <tt>Object[]</tt> value or <tt>null</tt>.
- **/
- public static Object[] getPropagatesAttribute(Module module)
- {
- Object value = module.getAttribute(PROPAGATES_ATTR);
- if (value != null)
- {
- return (Object[]) value;
- }
- return m_emptyProp;
- }
-
- /**
- * Utility method to determine if the specified module imports a given
- * import identifier, regardless of version. This method checks both
- * imports and exports, since a module is assumed to import what it exports.
- * @param module the module to check.
- * @param identifier the import identifier to check.
- * @return <tt>true</tt> if the module imports the specified
- * import identifier or <tt>false</tt> if it does not.
- **/
- public static boolean doesImport(Module module, Object identifier)
- {
- Object[][] imports = getImportsAttribute(module);
- for (int i = 0; i < imports.length; i++)
- {
- if (imports[i][IDENTIFIER_IDX].equals(identifier))
- {
- return true;
- }
- }
- imports = getExportsAttribute(module);
- for (int i = 0; i < imports.length; i++)
- {
- if (imports[i][IDENTIFIER_IDX].equals(identifier))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Utility method to create a list of modules that import from
- * the specified module.
- * @param mgr the module manager that contains the module.
- * @param module the module for which to create an importer list.
- * @return a list of modules that import from the specified module
- * or <tt>null</tt>.
- **/
- public static List createImporterList(ModuleManager mgr, Module module)
- {
- List list = null;
- Module[] modules = mgr.getModules();
- for (int modIdx = 0; modIdx < modules.length; modIdx++)
- {
- Object[][] imports = getImportsAttribute(modules[modIdx]);
- for (int impIdx = 0; impIdx < imports.length; impIdx++)
- {
- if (imports[impIdx][RESOLVING_MODULE_IDX] == module)
- {
- if (list == null)
- {
- list = new ArrayList();
- }
- list.add(modules[modIdx]);
- break;
- }
- }
- }
-
- return list;
- }
-
- /**
- * Utility method to get the import version number associated with a specific
- * import identifier of the specified module.
- * @param module the module to investigate.
- * @param identifier the import identifier for which the version should
- * be retrieved.
- * @return the version number object or <tt>null</tt>.
- **/
- public static Object getImportVersion(Module module, Object identifier)
- {
- Object[][] imports = getImportsAttribute(module);
- for (int i = 0; i < imports.length; i++)
- {
- if (imports[i][IDENTIFIER_IDX].equals(identifier))
- {
- return imports[i][VERSION_IDX];
- }
- }
- return null;
- }
-
- /**
- * Utility method to get the export version number associated with a specific
- * export identifier of the specified module.
- * @param module the module to investigate.
- * @param identifier the export identifier for which the version should
- * be retrieved.
- * @return the version number object or <tt>null</tt>.
- **/
- public static Object getExportVersion(Module module, Object identifier)
- {
- Object[][] exports = getExportsAttribute(module);
- for (int i = 0; i < exports.length; i++)
- {
- if (exports[i][IDENTIFIER_IDX].equals(identifier))
- {
- return exports[i][VERSION_IDX];
- }
- }
- return null;
- }
-
- /**
- * Utility method to get the resolving module of a specific import
- * identifier for the specified module.
- * @param module the module to investigate.
- * @param identifier the import identifier for which the resolving
- * module should be retrieved.
- * @return the resolving module or <tt>null</tt>.
- **/
- public static Module getImportResolvingModule(Module module, Object identifier)
- {
- Object[][] imports = getImportsAttribute(module);
-
- for (int i = 0; i < imports.length; i++)
- {
- if (imports[i][IDENTIFIER_IDX].equals(identifier))
- {
- return (Module) imports[i][RESOLVING_MODULE_IDX];
- }
- }
-
- return null;
- }
-
- /**
- * Utility method to get the resolving module of a specific export
- * identifier for the specified module.
- * @param module the module to investigate.
- * @param identifier the export identifier for which the resolving
- * module should be retrieved.
- * @return the resolving module or <tt>null</tt>.
- **/
- public static Module getExportResolvingModule(Module module, Object identifier)
- {
- Object[][] exports = getExportsAttribute(module);
-
- for (int i = 0; i < exports.length; i++)
- {
- if (exports[i][IDENTIFIER_IDX].equals(identifier))
- {
- return (Module) exports[i][RESOLVING_MODULE_IDX];
- }
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/SelectionPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/SelectionPolicy.java
deleted file mode 100644
index 2436bce..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/SelectionPolicy.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-import org.apache.felix.moduleloader.Module;
-
-/**
- * <p>
- * This interface represents the policy for selecting a specific export
- * target from multiple <i>compatible</i> candidate export targets when
- * the <tt>ImportSearchPolicy</tt> is trying to resolve an import target
- * for a given module. A concrete implementation of this interface is
- * required to create an instance of <tt>ImportSearchPolicy</tt>.
- * </p>
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy
-**/
-public interface SelectionPolicy
-{
- /**
- * Selects a single module to resolve the specified import
- * from the array of compatible candidate modules.
- * @param module the module that is importing the target.
- * @param identifier the identifier of the import target.
- * @param version the version number of the import target.
- * @param candidates array of compatible candidate modules from which to choose.
- * @param compatPolicy the compatibility policy that is being used.
- * @return the selected module or <tt>null</tt> if no module
- * can be selected.
- **/
- public Module select(
- Module module, Object identifier, Object version, Module[] candidates,
- CompatibilityPolicy compatPolicy);
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/SelfContainedSearchPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/SelfContainedSearchPolicy.java
deleted file mode 100644
index e2608c6..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/SelfContainedSearchPolicy.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-import java.net.URL;
-
-import org.apache.felix.moduleloader.*;
-
-/**
- * <p>
- * This class implements a <tt>ModuleLoader</tt> search policy that
- * assumes that all modules are self-contained. In other words, when
- * loading a class or resource for a particular module, only that
- * particular module's resource sources are search. No classes or
- * resources are shared among modules.
- * </p>
- * @see org.apache.felix.moduleloader.SearchPolicy
- * @see org.apache.felix.moduleloader.Module
- * @see org.apache.felix.moduleloader.ModuleClassLoader
- * @see org.apache.felix.moduleloader.ModuleManager
-**/
-public class SelfContainedSearchPolicy implements SearchPolicy
-{
- private ModuleManager m_mgr = null;
-
- /**
- * This method is part of the <tt>SearchPolicy</tt> interface.
- * This method is called by the <tt>ModuleManager</tt> once to
- * give the search policy instance a reference to its associated
- * module manager. This method should be implemented such that
- * it cannot be called twice; calling this method a second time
- * should produce an illegal state exception.
- * @param mgr the module manager associated with this search policy.
- * @throws java.lang.IllegalStateException if the method is called
- * more than once.
- **/
- public void setModuleManager(ModuleManager mgr)
- throws IllegalStateException
- {
- if (m_mgr == null)
- {
- m_mgr = mgr;
- }
- else
- {
- throw new IllegalStateException("Module manager is already initialized");
- }
- }
-
- public Object[] definePackage(Module module, String pkgName)
- {
- return null;
- }
-
- /**
- * Simply returns <tt>null</tt> which forces the module class
- * loader to only search the target module's resource sources
- * for the specified class.
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the class.
- * @param name the name of the class being loaded.
- * @return <tt>null</tt>.
- **/
- public Class findClassBeforeModule(ClassLoader parent, Module module, String name)
- {
- // First, try to load from parent.
- if (parent != null)
- {
- try
- {
- Class c = parent.loadClass(name);
- if (c != null)
- {
- return c;
- }
- }
- catch (ClassNotFoundException ex)
- {
- // Ignore.
- }
- }
-
- return null;
- }
-
- public Class findClassAfterModule(ClassLoader parent, Module module, String name)
- {
- return null;
- }
-
- /**
- * Simply returns <tt>null</tt> which forces the module class
- * loader to only search the target module's resource sources
- * for the specified resource.
- * @param parent the parent class loader of the delegating class loader.
- * @param module the target module that is loading the class.
- * @param name the name of the resource being loaded.
- * @return <tt>null</tt>.
- **/
- public URL findResource(ClassLoader parent, Module module, String name)
- {
- if (parent != null)
- {
- return parent.getResource(name);
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ValidationException.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ValidationException.java
deleted file mode 100644
index b996454..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ValidationException.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-import org.apache.felix.moduleloader.Module;
-
-/**
- * <p>
- * This exception is thrown if a module cannot be validated. The module
- * that failed to be validated is recorded, along with the failed import target
- * identifier and version number. If the error was a result of a propagation
- * conflict, then the propagation error flag is set.
- * </p>
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy#validate(org.apache.felix.moduleloader.Module)
-**/
-public class ValidationException extends Exception
-{
- private Module m_module = null;
- private Object m_identifier = null;
- private Object m_version = null;
- private boolean m_isPropagation = false;
-
- /**
- * Constructs an exception with the specified message, module,
- * import identifier, import version number, and propagation flag.
- **/
- public ValidationException(String msg, Module module,
- Object identifier, Object version, boolean isPropagation)
- {
- super(msg);
- m_module = module;
- m_identifier = identifier;
- m_version = version;
- m_isPropagation = isPropagation;
- }
-
- /**
- * Returns the module that was being validated.
- * @return the module that was being validated.
- **/
- public Module getModule()
- {
- return m_module;
- }
-
- /**
- * Returns the identifier of the import target that could not be resolved.
- * @return the identifier of the import target that could not be resolved.
- **/
- public Object getIdentifier()
- {
- return m_identifier;
- }
-
- /**
- * Returns the version number of the import target that could not be resolved.
- * @return the version number of the import target that could not be resolved.
- **/
- public Object getVersion()
- {
- return m_version;
- }
-
- /**
- * Returns a flag indicating whether the exception was caused by a
- * a propagation conflict.
- * @return <tt>true</tt> if the exception was thrown due to a propagation
- * conflict, <tt>false</tt> otherwise.
- **/
- public boolean isPropagationError()
- {
- return m_isPropagation;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ValidationListener.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ValidationListener.java
deleted file mode 100644
index 9491531..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/ValidationListener.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search;
-
-import java.util.EventListener;
-
-import org.apache.felix.moduleloader.ModuleEvent;
-
-/**
- * <p>
- * This is an event listener interface for listening to validation
- * events that are generated by the <tt>ImportSearchPolicy</tt>. Events
- * are fired when a module is validated and when it is invalidated.
- * </p>
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy
-**/
-public interface ValidationListener extends EventListener
-{
- /**
- * This is an event callback method that indicates that
- * a module was validated.
- * @param event the module event containing the event data.
- **/
- public void moduleValidated(ModuleEvent event);
-
- /**
- * This is an event callback method that indicates that
- * a module was invalidated.
- * @param event the module event containing the event data.
- **/
- public void moduleInvalidated(ModuleEvent event);
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/compatibility/ExactCompatibilityPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/compatibility/ExactCompatibilityPolicy.java
deleted file mode 100644
index f971683..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/compatibility/ExactCompatibilityPolicy.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search.compatibility;
-
-import org.apache.felix.moduleloader.search.CompatibilityPolicy;
-
-/**
- * This class implements a simple version numbering compatibility policy for the
- * <tt>ImportSearchPolicy</tt> where only exact version numbers are considered
- * to be compatible. This policy simply returns the result of
- * "<tt>leftId.equals(rightId) && leftVersion.equals(rightVersion)</tt>". Any
- * calls to the <tt>compare()</tt> method result in an exception since this
- * policy has no basis for comparing identifiers and versions.
- * @see org.apache.felix.moduleloader.search.CompatibilityPolicy
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy
-**/
-public class ExactCompatibilityPolicy implements CompatibilityPolicy
-{
- /**
- * Compares two versioned identifiers, but since this policy has
- * no understanding of how to compare identifiers, it always throws
- * an <tt>IllegalArgumentException</tt>.
- * @param leftId the identifier to test for compatibility.
- * @param leftVersion the version number to test for compatibility.
- * @param rightId the identifier used as the compatibility base line.
- * @param rightVersion the version used as the compatibility base line.
- * @return <tt>0</tt> if the identifiers are equal, <tt>-1</tt> if the
- * left identifier is less then the right identifier, and <tt>1</tt>
- * if the left identifier is greater than the right identifier.
- * @throws java.lang.IllegalArgumentException if the two identifiers
- * are not comparable, i.e., they refer to completely different
- * entities.
- **/
- public int compare(
- Object leftId, Object leftVersion,
- Object rightId, Object rightVersion)
- {
- throw new IllegalArgumentException("Identifiers are not comparable.");
- }
-
- /**
- * Returns whether the first import/export target is compatible
- * with the second. This method simply uses the "<tt>equals()</tt>" method
- * to test both the identifier and the verison number.
- * @param leftId the identifier to test for compatibility.
- * @param leftVersion the version number to test for compatibility.
- * @param rightId the identifier used as the compatibility base line.
- * @param rightVersion the version used as the compatibility base line.
- * @return <tt>true</tt> if the left version number object is compatible
- * with the right version number object, otherwise <tt>false</tt>.
- **/
- public boolean isCompatible(
- Object leftId, Object leftVersion,
- Object rightId, Object rightVersion)
- {
- return leftId.equals(rightId) && leftVersion.equals(rightVersion);
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/selection/InteractiveSelectionPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/selection/InteractiveSelectionPolicy.java
deleted file mode 100644
index f1ddee7..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/selection/InteractiveSelectionPolicy.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search.selection;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-
-import org.apache.felix.moduleloader.Module;
-import org.apache.felix.moduleloader.search.CompatibilityPolicy;
-import org.apache.felix.moduleloader.search.SelectionPolicy;
-
-/**
- * This class implements an interactive selection policy for the
- * <tt>ImportSearchPolicy</tt>. This policy simply uses standard
- * output to present the list of candidate modules and uses standard
- * input to allow the user to select a specific module from the
- * candidates. This selection policy is generally only useful for
- * debugging purposes.
- * @see org.apache.felix.moduleloader.search.SelectionPolicy
- * @see org.apache.felix.moduleloader.search.ImportSearchPolicy
-**/
-public class InteractiveSelectionPolicy implements SelectionPolicy
-{
- /**
- * Returns a single package from an array of packages.
- * @param sources array of packages from which to choose.
- * @return the selected package or <tt>null</tt> if no package
- * can be selected.
- **/
- public Module select(Module module, Object target,
- Object version, Module[] candidates, CompatibilityPolicy compatPolicy)
- {
- try {
- if (candidates.length == 1)
- {
- return candidates[0];
- }
- // Now start an interactive prompt.
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- do
- {
- System.out.println("\nImporting '" + target
- + "(" + version + ")" + "' for '" + module + "'.");
- System.out.println("");
- for (int i = 0; i < candidates.length; i++)
- {
- System.out.println((i + 1) + ". " + candidates[i]);
- }
- System.out.print("Select: ");
- String s = br.readLine();
-
- int choice = -1;
- try {
- choice = Integer.parseInt(s);
- } catch (Exception ex) {
- }
-
- if (choice == 0)
- {
- break;
- }
- else if ((choice > 0) && (choice <= candidates.length))
- {
- return candidates[choice - 1];
- }
- }
- while (true);
- } catch (Exception ex) {
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/selection/SimpleSelectionPolicy.java b/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/selection/SimpleSelectionPolicy.java
deleted file mode 100644
index a2f9648..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/search/selection/SimpleSelectionPolicy.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.moduleloader.search.selection;
-
-import java.util.*;
-
-import org.apache.felix.moduleloader.*;
-import org.apache.felix.moduleloader.search.*;
-
-/**
- * This class implements a reasonably simple selection policy for the
- * <tt>ImportSearchPolicy</tt>. When given a choice, this selection
- * policy will always select the newest version of the available
- * candidates to satisfy the import identifier. In the case where
- * a candidate has already been selected for a given import identifier,
- * then the previously selected module will be returned, if possible.
- * If it is not possible to return the previously selected module, then
- * a <tt>null</tt> is returned. This policy assumes that classes are
- * shared globally.
-**/
-public class SimpleSelectionPolicy implements SelectionPolicy, ModuleListener
-{
- private Map m_resolvedPackageMap = new HashMap();
- private Map m_resolvedModuleMap = new HashMap();
-
- /**
- * Selects a single module to resolve the specified import identifier
- * from the array of compatible candidate modules. If the import
- * identifier has not been resolved before, then this selection policy
- * chooses the module that exports the newest version of the
- * import identifer. If the import identifier has been resolved already,
- * then the same module that was chosen before is chosen again.
- * This ensures that all modules use the same version of all
- * exported classes.
- * @param module the module that is importing the target.
- * @param identifier the identifier of the import target.
- * @param version the version number of the import target.
- * @param candidates array of compatible candidate modules from which to choose.
- * @return the selected module or <tt>null</tt> if no module
- * can be selected.
- **/
- public synchronized Module select(Module module, Object identifier,
- Object version, Module[] candidates, CompatibilityPolicy compatPolicy)
- {
- // See if package is already resolved.
- Module selModule = (Module) m_resolvedPackageMap.get(identifier);
-
- // If no module was previously selected to export the package,
- // then try to choose one now.
- if (selModule == null)
- {
- Object selVersion = null;
-
- // Examine all exported instances of the identifier and
- // choose the one with the newest version number. If
- // there is more than one source for the newest version,
- // then just select the first one found.
- for (int i = 0; i < candidates.length; i++)
- {
- Object tmpVersion =
- ImportSearchPolicy.getExportVersion(candidates[i], identifier);
-
- // If this is the first comparison, then
- // just record it.
- if (selVersion == null)
- {
- selModule = candidates[i];
- selVersion = tmpVersion;
- }
- // If the current export package version is greater
- // than the selected export package version, then
- // record it instead.
- else if (compatPolicy.compare(identifier, tmpVersion, identifier, selVersion) >= 0)
- {
- selModule = candidates[i];
- selVersion = tmpVersion;
- }
- }
-
- m_resolvedPackageMap.put(identifier, selModule);
- m_resolvedModuleMap.put(selModule, selModule);
- }
- // See if the previously selected export module satisfies
- // the current request, otherwise return null.
- else
- {
- Object selVersion =
- ImportSearchPolicy.getExportVersion(selModule, identifier);
- Module tmpModule = selModule;
- selModule = null;
- if (compatPolicy.isCompatible(identifier, selVersion, identifier, version))
- {
- selModule = tmpModule;
- }
- }
-
- return selModule;
- }
-
- public void moduleAdded(ModuleEvent event)
- {
- }
-
- public void moduleReset(ModuleEvent event)
- {
- moduleRemoved(event);
- }
-
- public synchronized void moduleRemoved(ModuleEvent event)
- {
- // If the module that was removed was chosen for
- // exporting identifier, then flush it from our
- // data structures; we assume here that the application
- // will flush references to the removed module's classes.
- if (m_resolvedModuleMap.get(event.getModule()) != null)
- {
- // Remove from module map.
- m_resolvedModuleMap.remove(event.getModule());
- // Remove each exported package from package map.
- Iterator iter = m_resolvedPackageMap.entrySet().iterator();
- while (iter.hasNext())
- {
- Map.Entry entry = (Map.Entry) iter.next();
- if (entry.getValue() == event.getModule())
- {
- iter.remove();
- }
- }
- }
- }
-}
\ No newline at end of file