You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2006/01/27 14:01:25 UTC
svn commit: r372831 [2/2] -
/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/
Copied: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/SearchPolicyImpl.java (from r370894, incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java)
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/SearchPolicyImpl.java?p2=incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/SearchPolicyImpl.java&p1=incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java&r1=370894&r2=372831&rev=372831&view=diff
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java (original)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/SearchPolicyImpl.java Fri Jan 27 05:01:17 2006
@@ -1,19 +1,3 @@
-/*
- * 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.net.URL;
@@ -22,10 +6,9 @@
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;
+import org.osgi.framework.Version;
-public class R4SearchPolicy implements SearchPolicy, ModuleListener
+public class SearchPolicyImpl implements ISearchPolicy, ModuleListener
{
// Array of R4Package.
public static final String EXPORTS_ATTR = "exports";
@@ -39,7 +22,7 @@
public static final String RESOLVED_ATTR = "resolved";
private LogWrapper m_logger = null;
- private ModuleManager m_mgr = null;
+ private IModuleFactory m_factory = null;
private Map m_availPkgMap = new HashMap();
private Map m_inUsePkgMap = new HashMap();
@@ -48,25 +31,31 @@
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];
+ public static final IModule[] m_emptyModules = new IModule[0];
+ public static final IImport[] m_emptyImports= new IImport[0];
+ public static final IExport[] m_emptyExports= new IExport[0];
+ public static final IWire[] m_emptyWires = new IWire[0];
// Re-usable security manager for accessing class context.
private static SecurityManagerEx m_sm = new SecurityManagerEx();
- public R4SearchPolicy(LogWrapper logger)
+ public SearchPolicyImpl(LogWrapper logger)
{
m_logger = logger;
}
- public void setModuleManager(ModuleManager mgr)
+ public IModuleFactory getModuleFactory()
+ {
+ return m_factory;
+ }
+
+ public void setModuleFactory(IModuleFactory factory)
throws IllegalStateException
{
- if (m_mgr == null)
+ if (m_factory == null)
{
- m_mgr = mgr;
- m_mgr.addModuleListener(this);
+ m_factory = factory;
+ m_factory.addModuleListener(this);
}
else
{
@@ -74,27 +63,12 @@
}
}
- 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(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);
@@ -106,7 +80,7 @@
// potentially leak internal module information.
throw new ClassNotFoundException(
name + ": cannot resolve package "
- + ex.getPackage() + ".");
+ + ex.getPackage());
}
// Get the package of the target class.
@@ -116,70 +90,89 @@
// these packages cannot be provided by other bundles.
if (pkgName.startsWith("java."))
{
- return (parent == null) ? null : parent.loadClass(name);
+ 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 = getWiringAttr(module);
+ IWire[] wires = (IWire[]) module.getAttribute(WIRING_ATTR, m_emptyWires);
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))
+ // the same as the package for the wire.
+ if (wires[i].getExport().getName().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
+ // 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 = wires[i].getClass(name);
+ if (clazz != null)
{
- Class clazz = wires[i].m_module.getClassLoader().loadClassFromModule(name);
- if (clazz != null)
- {
- return clazz;
- }
+ return clazz;
}
- catch (Throwable th)
+ else
{
- // Not much we can do here.
+ throw new ClassNotFoundException(name);
}
- throw new ClassNotFoundException(name);
}
}
return null;
}
- public Class findClassAfterModule(ClassLoader parent, Module module, String name)
+ 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 own resources. Now we make an attempt to load the
+ // the module's content. 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);
+ IWire wire = 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);
+ // 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
@@ -202,7 +195,7 @@
// Get the class context to see the classes on the stack.
Class[] classes = m_sm.getClassContext();
- // Start from 1 to skip inner class.
+ // 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
@@ -214,9 +207,9 @@
// 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()))
+ if (!ContentClassLoader.class.isInstance(classes[i].getClassLoader()))
{
- return parent.loadClass(name);
+ return this.getClass().getClassLoader().loadClass(name);
}
break;
}
@@ -225,68 +218,163 @@
throw new ClassNotFoundException(name);
}
- public URL findResource(ClassLoader parent, Module module, String 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)
{
- return null;
+ // 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 resource.
+ // Get the package of the target class.
String pkgName = Util.getResourcePackage(name);
- // Load all "java.*" resources from parent class loader;
+ // 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.getResource(name);
+ return this.getClass().getClassLoader().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++)
+ // Look in the module's imports.
+ URL url = findImportedResource(module, name, pkgName);
+
+ // If not found, try the module's own content.
+ if (url == null)
{
- // Only check when the package of the resource is
- // the same as the import package.
- if (wires[i].m_pkg.getId().equals(pkgName))
+ url = module.getContentLoader().getResource(name);
+
+ // If still not found, then try the module's dynamic imports.
+ if (url == null)
{
- try
+ url = findDynamicallyImportedResource(module, name, pkgName);
+ }
+ }
+
+ if (url == null)
+ {
+ throw new ResourceNotFoundException(name);
+ }
+
+ return url;
+ }
+
+ private URL findImportedResource(IModule module, String name, String pkgName)
+ throws ResourceNotFoundException
+ {
+ // We delegate to the module's wires to find the class.
+ IWire[] wires = (IWire[]) module.getAttribute(WIRING_ATTR, m_emptyWires);
+ for (int i = 0; i < wires.length; i++)
+ {
+ // Only check when the package of the class is
+ // the same as the package for the wire.
+ if (wires[i].getExport().getName().equals(pkgName))
+ {
+ URL url = wires[i].getResource(name);
+ if (url != null)
{
- URL url = wires[i].m_module.getClassLoader().getResourceFromModule(name);
- if (url != null)
- {
- return url;
- }
+ return url;
}
- catch (Throwable th)
+ else
{
- // Not much we can do here.
+ throw new ResourceNotFoundException(name);
}
- throw new ResourceNotFoundException(name);
}
}
+
+ return null;
+ }
- // 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);
+ private URL findDynamicallyImportedResource(
+ IModule module, String name, String pkgName)
+ throws ResourceNotFoundException
+ {
+System.out.println("findDynamic " + name + " - " + pkgName);
+ // 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.
+ IWire 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 Module attemptDynamicImport(Module module, String pkgName)
+ private IWire attemptDynamicImport(IModule module, String pkgName)
{
- Module candidate = null;
+ IWire 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
@@ -296,27 +384,27 @@
{
// 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++)
+ IImport[] dynamics = (IImport[]) module.getAttribute(DYNAMICIMPORTS_ATTR, m_emptyImports);
+ IImport impMatch = null;
+ for (int i = 0; (impMatch == null) && (i < dynamics.length); i++)
{
// Star matches everything.
- if (dynamics[i].getId().equals("*"))
+ if (dynamics[i].getName().equals("*"))
{
// Create a package instance without wildcard.
- pkgMatch = new R4Package(
+ impMatch = new ImportImpl(
pkgName,
dynamics[i].getDirectives(),
dynamics[i].getAttributes());
}
// Packages ending in ".*" must match starting strings.
- else if (dynamics[i].getId().endsWith(".*"))
+ else if (dynamics[i].getName().endsWith(".*"))
{
if (pkgName.regionMatches(
- 0, dynamics[i].getId(), 0, dynamics[i].getId().length() - 2))
+ 0, dynamics[i].getName(), 0, dynamics[i].getName().length() - 2))
{
// Create a package instance without wildcard.
- pkgMatch = new R4Package(
+ impMatch = new ImportImpl(
pkgName,
dynamics[i].getDirectives(),
dynamics[i].getAttributes());
@@ -325,9 +413,9 @@
// Or we can have a precise match.
else
{
- if (pkgName.equals(dynamics[i].getId()))
+ if (pkgName.equals(dynamics[i].getName()))
{
- pkgMatch = dynamics[i];
+ impMatch = dynamics[i];
}
}
}
@@ -336,7 +424,7 @@
// 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))
+ if ((impMatch == null) || (getWire(module, impMatch.getName()) != null))
{
return null;
}
@@ -347,14 +435,14 @@
// of wires.
// Lock module manager instance to ensure that nothing changes.
- synchronized (m_mgr)
+ 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.
- Module[] candidates = getCompatibleExporters(
- (Module[]) m_inUsePkgMap.get(pkgMatch.getId()), pkgMatch);
+ 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)
{
@@ -366,7 +454,7 @@
if (candidate == null)
{
candidates = getCompatibleExporters(
- (Module[]) m_availPkgMap.get(pkgMatch.getId()), pkgMatch);
+ (IModule[]) m_availPkgMap.get(impMatch.getName()), impMatch);
for (int candIdx = 0;
(candidate == null) && (candIdx < candidates.length);
candIdx++)
@@ -386,14 +474,16 @@
// wiring attribute.
if (candidate != null)
{
- R4Wire[] wires = getWiringAttr(module);
- R4Wire[] newWires = new R4Wire[wires.length + 1];
+ IWire[] wires = (IWire[]) module.getAttribute(WIRING_ATTR, m_emptyWires);
+ IWire[] newWires = new IWire[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);
+ wire = new WireImpl(
+ module, candidate,
+ getExportPackage(candidate, impMatch.getName()));
+ newWires[wires.length] = wire;
module.setAttribute(WIRING_ATTR, newWires);
m_logger.log(LogWrapper.LOG_DEBUG, "WIRE: [" + module + "] " + newWires[wires.length]);
}
@@ -404,45 +494,50 @@
m_logger.log(LogWrapper.LOG_ERROR, "Unable to dynamically import package.", ex);
}
- return candidate;
+ return wire;
+ }
+
+ public URL createURL(IModule module, String path)
+ {
+ return null;
}
- public Module[] getAvailableExporters(R4Package pkg)
+ public IModule[] getAvailableExporters(IImport pkg)
{
// Synchronized on the module manager to make sure that no
// modules are added, removed, or resolved.
- synchronized (m_mgr)
+ synchronized (m_factory)
{
- return getCompatibleExporters((Module[]) m_availPkgMap.get(pkg.getId()), pkg);
+ return getCompatibleExporters((IModule[]) m_availPkgMap.get(pkg.getName()), pkg);
}
}
- public Module[] getInUseExporters(R4Package pkg)
+ public IModule[] getInUseExporters(IImport pkg)
{
// Synchronized on the module manager to make sure that no
// modules are added, removed, or resolved.
- synchronized (m_mgr)
+ synchronized (m_factory)
{
- return getCompatibleExporters((Module[]) m_inUsePkgMap.get(pkg.getId()), pkg);
+ return getCompatibleExporters((IModule[]) m_inUsePkgMap.get(pkg.getName()), pkg);
}
}
- public void resolve(Module rootModule)
+ public void resolve(IModule rootModule)
throws ResolveException
{
// If the module is already resolved, then we can just return.
- if (getResolvedAttr(rootModule).booleanValue())
+ if (((Boolean) rootModule.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).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.
@@ -451,7 +546,7 @@
// 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)
+ synchronized (m_factory)
{
// The first step is to populate the resolver map. This
// will use the target module to populate the resolver map
@@ -466,8 +561,6 @@
// 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"
@@ -480,7 +573,7 @@
// 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.
@@ -490,7 +583,7 @@
// The resolved module wire map maps a module to its array of
// wires.
resolvedModuleWireMap = createWires(resolverMap, rootModule);
-
+
//dumpAvailablePackages();
//dumpUsedPackages();
@@ -504,12 +597,12 @@
Iterator iter = resolvedModuleWireMap.entrySet().iterator();
while (iter.hasNext())
{
- fireModuleResolved((Module) ((Map.Entry) iter.next()).getKey());
+ fireModuleResolved((IModule) ((Map.Entry) iter.next()).getKey());
}
}
}
- private void populateResolverMap(Map resolverMap, Module module)
+ private void populateResolverMap(Map resolverMap, IModule module)
throws ResolveException
{
// Detect cycles.
@@ -529,20 +622,20 @@
// Loop through each import and calculate its resolving
// set of candidates.
- R4Package[] imports = getImportsAttr(module);
+ IImport[] imports = (IImport[]) module.getAttribute(IMPORTS_ATTR, m_emptyImports);
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];
+ 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);
@@ -557,7 +650,7 @@
{
// Only populate the resolver map with modules that
// are not already resolved.
- if (!getResolvedAttr(candidates[candIdx]).booleanValue())
+ if (!((Boolean) candidates[candIdx].getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue())
{
populateResolverMap(resolverMap, candidates[candIdx]);
}
@@ -606,27 +699,70 @@
}
}
- /**
- * <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)
+
+// 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]);
+ }
+ }
+ }
+ }
+
+ protected IModule[] getCompatibleExporters(IModule[] modules, IImport 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.
+ IExport export = 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.
@@ -649,47 +785,47 @@
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, Module rootModule, Map cycleMap)
+ 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 (getResolvedAttr(rootModule).booleanValue() ||
+ if (((Boolean) rootModule.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).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);
+ IExport[] exports = (IExport[]) rootModule.getAttribute(EXPORTS_ATTR, m_emptyExports);
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)
+ if (getImportPackage(rootModule, exports[i].getName()) == null)
{
- usesMap.put(exports[i].getId(), rootModule);
+ 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
@@ -704,10 +840,10 @@
// 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(
@@ -715,12 +851,12 @@
{
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());
-
+ IExport candidatePkg = 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.
@@ -749,38 +885,38 @@
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, Module module, R4Package exportPkg, Map usesMap)
+ Map resolverMap, IModule module, IExport 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(exportPkg.getId()) != null)
+ if (usesMap.get(export.getName()) != null)
{
return usesMap;
}
// The target package at least uses itself,
// so add it to the uses map.
- usesMap.put(exportPkg.getId(), module);
+ 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 = exportPkg.getUses();
+ String[] uses = export.getUses();
List nodeList = (List) resolverMap.get(module);
// We need to walk the transitive closure of "uses" relationships
@@ -803,19 +939,19 @@
// 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]);
+ IWire wire = getWire(module, uses[usesIdx]);
if (wire != null)
{
usesMap = calculateUsesDependencies(
- resolverMap, wire.m_module, wire.m_pkg, usesMap);
+ resolverMap, wire.getExportingModule(), wire.getExport(), usesMap);
}
else
{
- exportPkg = getExportPackage(module, uses[usesIdx]);
- if (exportPkg != null)
+ export = getExportPackage(module, uses[usesIdx]);
+ if (export != null)
{
usesMap = calculateUsesDependencies(
- resolverMap, module, exportPkg, usesMap);
+ resolverMap, module, export, usesMap);
}
}
}
@@ -829,7 +965,7 @@
nodeIdx++)
{
node = (ResolverNode) nodeList.get(nodeIdx);
- if (!node.m_pkg.getId().equals(uses[usesIdx]))
+ if (!node.m_import.getName().equals(uses[usesIdx]))
{
node = null;
}
@@ -844,7 +980,7 @@
usesMap = calculateUsesDependencies(
resolverMap,
node.m_candidates[node.m_idx],
- getExportPackage(node.m_candidates[node.m_idx], node.m_pkg.getId()),
+ getExportPackage(node.m_candidates[node.m_idx], node.m_import.getName()),
usesMap);
}
// If there was no resolver node for the "used" package,
@@ -865,32 +1001,6 @@
return usesMap;
}
- /**
- * <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
{
@@ -920,7 +1030,7 @@
"Unable to resolve due to constraint violation.", null, null);
}
- private Map createWires(Map resolverMap, Module rootModule)
+ private Map createWires(Map resolverMap, IModule rootModule)
{
Map resolvedModuleWireMap =
populateWireMap(resolverMap, rootModule, new HashMap());
@@ -928,9 +1038,9 @@
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
- Module module = (Module) entry.getKey();
- R4Wire[] wires = (R4Wire[]) entry.getValue();
-
+ IModule module = (IModule) entry.getKey();
+ IWire[] wires = (IWire[]) entry.getValue();
+
// Set the module's resolved and wiring attribute.
module.setAttribute(RESOLVED_ATTR, Boolean.TRUE);
// Only add wires attribute if some exist; export
@@ -939,7 +1049,7 @@
{
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.
@@ -949,10 +1059,10 @@
{
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);
-
+ 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
@@ -961,291 +1071,81 @@
// 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)
+ if (wires[wireIdx].getExportingModule() != module)
{
- modules = (Module[]) m_availPkgMap.get(wires[wireIdx].m_pkg.getId());
+ modules = (IModule[]) m_availPkgMap.get(wires[wireIdx].getExport().getName());
modules = removeModuleFromArray(modules, module);
- m_availPkgMap.put(wires[wireIdx].m_pkg.getId(), modules);
+ m_availPkgMap.put(wires[wireIdx].getExport().getName(), 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);
+ 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, Module module, Map wireMap)
+ 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 (getResolvedAttr(module).booleanValue() ||
+ if (((Boolean) module.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue() ||
(wireMap.get(module) != null))
{
return wireMap;
}
-
+
List nodeList = (List) resolverMap.get(module);
- R4Wire[] wires = new R4Wire[nodeList.size()];
-
+ IWire[] wires = new IWire[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]);
-
+ IExport export =
+ getExportPackage(node.m_candidates[node.m_idx], node.m_import.getName());
+ wires[nodeIdx] = new WireImpl(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;
}
-// TODO: REMOVE THESE DEBUG METHODS.
- private void dumpResolverMap(Map resolverMap)
+ //
+ // 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)
{
- Iterator iter = resolverMap.entrySet().iterator();
- while (iter.hasNext())
+ // Verify listener.
+ if (l == null)
{
- 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]);
- }
+ throw new IllegalArgumentException("Listener is null");
}
- }
- private void dumpAvailablePackages()
- {
- synchronized (m_mgr)
+ // Use the m_noListeners object as a lock.
+ synchronized (m_emptyListeners)
{
- 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]);
- }
- }
- }
- }
-
- private void dumpUsedPackages()
- {
- 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]);
- }
- }
- }
- }
-
- /**
- * 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)
+ // If we have no listeners, then just add the new listener.
+ if (m_listeners == m_emptyListeners)
{
m_listeners = new ResolveListener[] { l };
}
@@ -1322,7 +1222,7 @@
* Fires a validation event for the specified module.
* @param module the module that was resolved.
**/
- protected void fireModuleResolved(Module module)
+ protected void fireModuleResolved(IModule module)
{
// Event holder.
ModuleEvent event = null;
@@ -1337,7 +1237,7 @@
// Lazily create event.
if (event == null)
{
- event = new ModuleEvent(m_mgr, module);
+ event = new ModuleEvent(m_factory, module);
}
listeners[i].moduleResolved(event);
}
@@ -1347,7 +1247,7 @@
* Fires an unresolved event for the specified module.
* @param module the module that was unresolved.
**/
- protected void fireModuleUnresolved(Module module)
+ protected void fireModuleUnresolved(IModule module)
{
// Event holder.
ModuleEvent event = null;
@@ -1362,60 +1262,145 @@
// Lazily create event.
if (event == null)
{
- event = new ModuleEvent(m_mgr, module);
+ event = new ModuleEvent(m_factory, module);
}
listeners[i].moduleUnresolved(event);
}
}
- //
- // Static utility methods.
- //
+ 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_factory)
+ {
+ // 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.
+ IExport[] exports = (IExport[]) event.getModule().getAttribute(EXPORTS_ATTR, m_emptyExports);
+ for (int i = 0; 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[] { event.getModule() };
+ }
+ else
+ {
+ int top = 0, bottom = modules.length - 1, middle = 0;
+ Version middleVersion = null;
+ while (top <= bottom)
+ {
+ middle = (bottom - top) / 2 + top;
+ middleVersion = 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 = getBundleIdFromModuleId(modules[middle].getId());
+ long exportId = getBundleIdFromModuleId(event.getModule().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] = event.getModule();
+ modules = newMods;
+ }
+
+ m_availPkgMap.put(exports[i].getName(), modules);
+ }
+ }
+ }
- public static Boolean getResolvedAttr(Module m)
+ // 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)
{
- Boolean b =
- (Boolean) m.getAttribute(RESOLVED_ATTR);
- if (b == null)
+ try
{
- b = Boolean.FALSE;
+ String bundleId = (id.indexOf('.') >= 0)
+ ? id.substring(0, id.indexOf('.')) : id;
+ return Long.parseLong(bundleId);
+ }
+ catch (NumberFormatException ex)
+ {
+ return -1;
}
- return b;
}
- public static R4Package[] getExportsAttr(Module m)
+ public void moduleReset(ModuleEvent event)
{
- R4Package[] attr =
- (R4Package[]) m.getAttribute(EXPORTS_ATTR);
- return (attr == null) ? m_emptyPackages : attr;
+ moduleRemoved(event);
}
- public static R4Package getExportPackage(Module m, String id)
+ public void moduleRemoved(ModuleEvent event)
{
- R4Package[] pkgs = getExportsAttr(m);
- for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
+ // 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_factory)
{
- if (pkgs[i].getId().equals(id))
+ // Remove exports from package maps.
+ IExport[] exports = (IExport[]) event.getModule().getAttribute(EXPORTS_ATTR, m_emptyExports);
+ for (int i = 0; i < exports.length; i++)
{
- return pkgs[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);
+ }
}
}
- return null;
}
- public static R4Package[] getImportsAttr(Module m)
+ public static IExport getExportPackage(IModule m, String name)
{
- 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);
+ IExport[] pkgs = (IExport[]) m.getAttribute(EXPORTS_ATTR, m_emptyExports);
for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
{
- if (pkgs[i].getId().equals(id))
+ if (pkgs[i].getName().equals(name))
{
return pkgs[i];
}
@@ -1423,19 +1408,12 @@
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)
+ public static IImport getImportPackage(IModule m, String name)
{
- R4Package[] pkgs = getDynamicImportsAttr(m);
+ IImport[] pkgs = (IImport[]) m.getAttribute(IMPORTS_ATTR, m_emptyImports);
for (int i = 0; (pkgs != null) && (i < pkgs.length); i++)
{
- if (pkgs[i].getId().equals(id))
+ if (pkgs[i].getName().equals(name))
{
return pkgs[i];
}
@@ -1443,23 +1421,12 @@
return null;
}
- public static R4Wire[] getWiringAttr(Module m)
+ public static IWire getWire(IModule m, String name)
{
- 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);
+ IWire[] wires = (IWire[]) m.getAttribute(WIRING_ATTR, m_emptyWires);
for (int i = 0; (wires != null) && (i < wires.length); i++)
{
- if (wires[i].m_pkg.getId().equals(id))
+ if (wires[i].getExport().getName().equals(name))
{
return wires[i];
}
@@ -1467,21 +1434,7 @@
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)
+ public 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++)
@@ -1494,20 +1447,20 @@
if (modules != null)
{
- Module[] newModules = new Module[modules.length + 1];
+ IModule[] newModules = new IModule[modules.length + 1];
System.arraycopy(modules, 0, newModules, 0, modules.length);
newModules[modules.length] = m;
modules = newModules;
}
else
{
- modules = new Module[] { m };
+ modules = new IModule[] { m };
}
return modules;
}
- public static Module[] removeModuleFromArray(Module[] modules, Module m)
+ public static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
{
if (modules == null)
{
@@ -1534,7 +1487,7 @@
// Otherwise, we need to do some array copying.
else
{
- Module[] newModules= new Module[modules.length - 1];
+ IModule[] newModules= new IModule[modules.length - 1];
System.arraycopy(modules, 0, newModules, 0, idx);
if (idx < newModules.length)
{
@@ -1547,41 +1500,7 @@
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)
+ private static IModule[] shrinkModuleArray(IModule[] modules)
{
if (modules == null)
{
@@ -1599,7 +1518,7 @@
if (count > 0)
{
- Module[] newModules = new Module[modules.length - count];
+ IModule[] newModules = new IModule[modules.length - count];
count = 0;
for (int i = 0; i < modules.length; i++)
{
@@ -1616,17 +1535,17 @@
private static class ResolverNode
{
- public Module m_module = null;
- public R4Package m_pkg = null;
- public Module[] m_candidates = null;
+ public IModule m_module = null;
+ public IImport m_import = null;
+ public IModule[] m_candidates = null;
public int m_idx = 0;
public boolean m_visited = false;
- public ResolverNode(Module module, R4Package pkg, Module[] candidates)
+ public ResolverNode(IModule module, IImport imp, IModule[] candidates)
{
m_module = module;
- m_pkg = pkg;
+ m_import = imp;
m_candidates = candidates;
- if (getResolvedAttr(m_module).booleanValue())
+ if (((Boolean) m_module.getAttribute(RESOLVED_ATTR, Boolean.FALSE)).booleanValue())
{
m_visited = true;
}
Added: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java
URL: http://svn.apache.org/viewcvs/incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java?rev=372831&view=auto
==============================================================================
--- incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java (added)
+++ incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java Fri Jan 27 05:01:17 2006
@@ -0,0 +1,50 @@
+package org.apache.felix.framework.searchpolicy;
+
+import java.net.*;
+import java.security.AccessController;
+
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.moduleloader.IModule;
+import org.apache.felix.moduleloader.IURLPolicy;
+
+public class URLPolicyImpl implements IURLPolicy
+{
+ private URLStreamHandler m_streamHandler = null;
+
+ public URLPolicyImpl(URLStreamHandler streamHandler)
+ {
+ m_streamHandler = streamHandler;
+ }
+
+ public URL createURL(IModule module, 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;
+ }
+
+// TODO: FIX CREATE PRIVILEGED URL, SEE OSGiURLPolicy:93.
+ 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, path, m_streamHandler);
+ }
+ }
+ catch (MalformedURLException ex)
+ {
+// TODO: FIX LOGGING.
+ ex.printStackTrace();
+ }
+ return null;
+ }
+}
\ No newline at end of file
Propchange: incubator/felix/sandbox/rickhall/framework-branch/src/main/java/org/apache/felix/framework/searchpolicy/URLPolicyImpl.java
------------------------------------------------------------------------------
svn:eol-style = native