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 2008/12/23 21:07:49 UTC
svn commit: r729083 [1/3] - in
/felix/trunk/framework/src/main/java/org/apache/felix/framework: ./
searchpolicy/
Author: rickhall
Date: Tue Dec 23 12:07:49 2008
New Revision: 729083
URL: http://svn.apache.org/viewvc?rev=729083&view=rev
Log:
Started refactoring of resolver code, breaking R4SearchPolicyCore into
the class loader delegation portion and the resolver portion. (FELIX-851)
Added:
felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ResolvedPackage.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=729083&r1=729082&r2=729083&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Tue Dec 23 12:07:49 2008
@@ -27,6 +27,8 @@
import org.apache.felix.framework.cache.*;
import org.apache.felix.framework.ext.SecurityProvider;
import org.apache.felix.framework.searchpolicy.*;
+import org.apache.felix.framework.searchpolicy.PackageSource;
+import org.apache.felix.framework.searchpolicy.Resolver.ResolverState;
import org.apache.felix.framework.util.*;
import org.apache.felix.framework.util.manifestparser.*;
import org.apache.felix.moduleloader.*;
@@ -52,6 +54,9 @@
// MODULE FACTORY.
private IModuleFactory m_factory = null;
+ private final Resolver m_resolver;
+ private final FelixResolverState m_resolverState;
+ private final FelixResolver m_felixResolver;
private R4SearchPolicyCore m_policyCore = null;
// Lock object used to determine if an individual bundle
@@ -283,74 +288,16 @@
// Create default bundle stream handler.
m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
- // Create search policy for module loader.
- m_policyCore = new R4SearchPolicyCore(m_logger, m_configMap);
+ // Create a resolver and its state.
+ m_resolver = new Resolver(m_logger);
+ m_resolverState = new FelixResolverState(m_logger);
+ m_felixResolver = new FelixResolver(m_resolver, m_resolverState);
- // 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.
- m_policyCore.addResolverListener(new ResolveListener() {
- public void moduleResolved(ModuleEvent event)
- {
- FelixBundle bundle = null;
- try
- {
- long id = Util.getBundleIdFromModuleId(
- event.getModule().getId());
- if (id > 0)
- {
- // Update the bundle's state to resolved when the
- // current module is resolved; just ignore resolve
- // events for older revisions since this only occurs
- // when an update is done on an unresolved bundle
- // and there was no refresh performed.
- bundle = (FelixBundle) getBundle(id);
-
- // Lock the bundle first.
- try
- {
- acquireBundleLock(bundle);
- if (bundle.getInfo().getCurrentModule() == event.getModule())
- {
- if (bundle.getInfo().getState() != Bundle.INSTALLED)
- {
- m_logger.log(
- Logger.LOG_WARNING,
- "Received a resolve event for a bundle that has already been resolved.");
- }
- else
- {
- bundle.getInfo().setState(Bundle.RESOLVED);
- fireBundleEvent(BundleEvent.RESOLVED, bundle);
- }
- }
- }
- finally
- {
- releaseBundleLock(bundle);
- }
- }
- }
- catch (NumberFormatException ex)
- {
- // Ignore.
- }
- }
-
- public void moduleUnresolved(ModuleEvent event)
- {
- // We can ignore this, because the only time it
- // should happen is when a refresh occurs. The
- // refresh operation resets the bundle's state
- // by calling BundleInfo.reset(), thus it is not
- // necessary for us to reset the bundle's state
- // here.
- }
- });
+ // Create search policy for module loader.
+ m_policyCore = new R4SearchPolicyCore(m_logger, m_configMap, m_felixResolver);
// Create the module factory and attach it to the search policy.
m_factory = new ModuleFactoryImpl(m_logger);
- m_policyCore.setModuleFactory(m_factory);
// Create the system bundle info object, which will hold state info.
m_sbi = new SystemBundleInfo(m_logger, null);
@@ -358,6 +305,7 @@
// definition for creating the system bundle module.
m_extensionManager = new ExtensionManager(m_logger, m_configMap, m_sbi);
m_sbi.addModule(m_factory.createModule("0", m_extensionManager));
+ m_resolverState.addModule(m_sbi.getCurrentModule());
// Set the extension manager as the content loader for the system
// bundle module.
m_extensionManager.setSearchPolicy(
@@ -749,7 +697,7 @@
// state to be set to RESOLVED.
try
{
- m_policyCore.resolve(m_sbi.getCurrentModule());
+ m_felixResolver.resolve(m_sbi.getCurrentModule());
}
catch (ResolveException ex)
{
@@ -1783,7 +1731,7 @@
IModule module = bundle.getInfo().getCurrentModule();
try
{
- m_policyCore.resolve(module);
+ m_felixResolver.resolve(module);
}
catch (ResolveException ex)
{
@@ -2989,8 +2937,8 @@
protected ExportedPackage[] getExportedPackages(String pkgName)
{
// First, get all exporters of the package.
- R4SearchPolicyCore.PackageSource[] exporters =
- m_policyCore.getResolvedCandidates(
+ PackageSource[] exporters =
+ m_resolverState.getResolvedCandidates(
new Requirement(
ICapability.PACKAGE_NAMESPACE,
null,
@@ -3120,7 +3068,7 @@
// "in use" exporters of the package.
if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
{
- R4SearchPolicyCore.PackageSource[] inUseModules = m_policyCore.getResolvedCandidates(
+ PackageSource[] inUseModules = m_resolverState.getResolvedCandidates(
new Requirement(
ICapability.PACKAGE_NAMESPACE,
null,
@@ -3478,6 +3426,7 @@
// Create the module using the module definition.
IModule module = m_factory.createModule(
Long.toString(targetId) + "." + Integer.toString(revision), md);
+ m_resolverState.addModule(module);
// Create the content loader from the module archive.
IContentLoader contentLoader = new ContentLoaderImpl(
@@ -3513,6 +3462,11 @@
// has not yet been added to the bundle to be removed later.
m_factory.removeModule(module);
throw new BundleException("Native library does not exist: " + entryName);
+// TODO: REFACTOR - We have a memory leak here since we added a module above
+// and then don't remove it in case of an error; this may also
+// be a general issue for installing/updating bundles, so check.
+// This will likely go away when we refactor out the module
+// factory, but we will track it under FELIX-835 until then.
}
}
}
@@ -3575,6 +3529,7 @@
for (int i = 0; i < modules.length; i++)
{
m_factory.removeModule(modules[i]);
+ m_resolverState.removeModule(modules[i]);
}
// Purge all bundle revisions, but the current one.
@@ -3599,6 +3554,7 @@
for (int i = 0; i < modules.length; i++)
{
m_factory.removeModule(modules[i]);
+ m_resolverState.removeModule(modules[i]);
}
// Remove the bundle from the cache.
@@ -3818,6 +3774,191 @@
// Miscellaneous inner classes.
//
+ public class FelixResolver
+ {
+ private final Resolver m_resolver;
+ private final FelixResolverState m_resolverState;
+
+ public FelixResolver(Resolver resolver, FelixResolverState resolverState)
+ {
+ m_resolver = resolver;
+ m_resolverState = resolverState;
+ }
+
+ public void resolve(IModule rootModule) throws ResolveException
+ {
+ if (!m_resolverState.isResolved(rootModule))
+ {
+ Resolver.Result result = m_resolver.resolve(m_resolverState, rootModule);
+
+ // Mark all modules as resolved.
+ markResolvedModules(result.m_resolvedModuleWireMap);
+
+ // Attach and mark all fragments as resolved.
+ attachFragments(result.m_host, result.m_fragmentMap);
+ }
+ }
+
+ public IWire resolveDynamicImport(IModule importer, String pkgName) throws ResolveException
+ {
+ IWire candidateWire = null;
+
+ if (m_resolverState.isResolved(importer))
+ {
+ Object[] result = m_resolver.resolveDynamicImport(m_resolverState, importer, pkgName);
+ if (result != null)
+ {
+ candidateWire = (IWire) result[0];
+ Map resolvedModuleWireMap = (Map) result[1];
+
+ // Mark all modules as resolved.
+ markResolvedModules(resolvedModuleWireMap);
+
+ // Dynamically add new wire to importing module.
+ if (candidateWire != null)
+ {
+ IWire[] wires = importer.getWires();
+ IWire[] newWires = null;
+ if (wires == null)
+ {
+ newWires = new IWire[1];
+ }
+ else
+ {
+ newWires = new IWire[wires.length + 1];
+ System.arraycopy(wires, 0, newWires, 0, wires.length);
+ }
+
+ newWires[newWires.length - 1] = candidateWire;
+ ((ModuleImpl) importer).setWires(newWires);
+m_logger.log(Logger.LOG_DEBUG, "DYNAMIC WIRE: " + newWires[newWires.length - 1]);
+ }
+ }
+ }
+
+ return candidateWire;
+ }
+
+ public synchronized PackageSource[] getResolvedCandidates(IRequirement req)
+ {
+ return m_resolverState.getResolvedCandidates(req);
+ }
+
+ public synchronized PackageSource[] getUnresolvedCandidates(IRequirement req)
+ {
+ return m_resolverState.getUnresolvedCandidates(req);
+ }
+
+ private void markResolvedModules(Map resolvedModuleWireMap)
+ {
+ Iterator iter = resolvedModuleWireMap.entrySet().iterator();
+ // Iterate over the map to mark the modules as resolved and
+ // update our resolver data structures.
+ while (iter.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ IModule module = (IModule) entry.getKey();
+ IWire[] wires = (IWire[]) entry.getValue();
+
+ // Only add wires attribute if some exist; export
+ // only modules may not have wires.
+ if (wires.length > 0)
+ {
+ ((ModuleImpl) module).setWires(wires);
+for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
+{
+ m_logger.log(Logger.LOG_DEBUG, "WIRE: " + wires[wireIdx]);
+}
+ }
+
+ // Update the resolver state to show the module as resolved.
+ m_resolverState.setResolved(module, true);
+ // Update the state of the module's bundle to resolved as well.
+ markBundleResolved(module);
+ }
+ }
+
+ private void attachFragments(IModule host, Map fragmentMap)
+ {
+ // Attach fragments to host module.
+ if ((fragmentMap != null) && (fragmentMap.size() > 0))
+ {
+ List list = new ArrayList();
+ for (Iterator iter = fragmentMap.entrySet().iterator(); iter.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String symName = (String) entry.getKey();
+ IModule[] fragments = (IModule[]) entry.getValue();
+// TODO: FRAGMENT - For now, just attach first candidate.
+ list.add(fragments[0]);
+m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: "
+ + host + " -> " + symName + " -> " + fragments[0]);
+
+ // Update the resolver state to show the module as resolved.
+ m_resolverState.setResolved(fragments[0], true);
+ // Update the state of the module's bundle to resolved as well.
+ markBundleResolved(fragments[0]);
+ }
+ try
+ {
+ ((ModuleImpl) host).attachFragments(
+ (IModule[]) list.toArray(new IModule[list.size()]));
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Unable to attach fragments", ex);
+ }
+ }
+ }
+
+ private void markBundleResolved(IModule module)
+ {
+ // Mark associated bundle as resolved.
+ try
+ {
+ long id = Util.getBundleIdFromModuleId(module.getId());
+ if (id > 0)
+ {
+ // Update the bundle's state to resolved when the
+ // current module is resolved; just ignore resolve
+ // events for older revisions since this only occurs
+ // when an update is done on an unresolved bundle
+ // and there was no refresh performed.
+ FelixBundle bundle = (FelixBundle) getBundle(id);
+
+ // Lock the bundle first.
+ try
+ {
+// TODO: RESOLVER - Seems like we should release the lock before we fire the event.
+ acquireBundleLock(bundle);
+ if (bundle.getInfo().getCurrentModule() == module)
+ {
+ if (bundle.getInfo().getState() != Bundle.INSTALLED)
+ {
+ m_logger.log(
+ Logger.LOG_WARNING,
+ "Received a resolve event for a bundle that has already been resolved.");
+ }
+ else
+ {
+ bundle.getInfo().setState(Bundle.RESOLVED);
+ fireBundleEvent(BundleEvent.RESOLVED, bundle);
+ }
+ }
+ }
+ finally
+ {
+ releaseBundleLock(bundle);
+ }
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ // Ignore.
+ }
+ }
+ }
+
class SystemBundleActivator implements BundleActivator, Runnable
{
public void start(BundleContext context) throws Exception
@@ -3895,6 +4036,7 @@
try
{
m_factory.removeModule(modules[j]);
+ m_resolverState.removeModule(modules[j]);
}
catch (Exception ex)
{
Added: felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java?rev=729083&view=auto
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java (added)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java Tue Dec 23 12:07:49 2008
@@ -0,0 +1,735 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.felix.framework.searchpolicy.Resolver;
+import org.apache.felix.framework.searchpolicy.PackageSource;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.Requirement;
+import org.apache.felix.moduleloader.ICapability;
+import org.apache.felix.moduleloader.IModule;
+import org.apache.felix.moduleloader.IRequirement;
+import org.apache.felix.moduleloader.IWire;
+import org.apache.felix.moduleloader.ModuleImpl;
+import org.osgi.framework.Constants;
+import org.osgi.framework.PackagePermission;
+import org.osgi.framework.Version;
+
+public class FelixResolverState implements Resolver.ResolverState
+{
+ private final Logger m_logger;
+ // List of all modules.
+ private final List m_moduleList = new ArrayList();
+ // Maps a package name to an array of modules.
+ private final Map m_unresolvedPkgIndexMap = new HashMap();
+ // Maps a package name to an array of modules.
+ private final Map m_resolvedPkgIndexMap = new HashMap();
+ // Maps a module to an array of capabilities.
+ private final Map m_resolvedCapMap = new HashMap();
+
+ private final Map m_moduleDataMap = new HashMap();
+
+ // Reusable empty array.
+ private static final IModule[] m_emptyModules = new IModule[0];
+ private static final PackageSource[] m_emptySources = new PackageSource[0];
+
+ public FelixResolverState(Logger logger)
+ {
+ m_logger = logger;
+ }
+
+ public synchronized void addModule(IModule module)
+ {
+ // When a module is added, create an aggregated list of unresolved
+ // exports to simplify later processing when resolving bundles.
+ m_moduleList.add(module);
+
+ ICapability[] caps = module.getDefinition().getCapabilities();
+
+ // Add exports to unresolved package map.
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ indexPackageCapability(m_unresolvedPkgIndexMap, module, caps[i]);
+ }
+ }
+
+System.out.println("UNRESOLVED PACKAGES:");
+dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+System.out.println("RESOLVED PACKAGES:");
+dumpPackageIndexMap(m_resolvedPkgIndexMap);
+ }
+
+ public synchronized void removeModule(IModule module)
+ {
+ // When a module is removed from the system, we need remove
+ // its exports from the "resolved" and "unresolved" package maps,
+ // remove the module's dependencies on fragments and exporters,
+ // and remove the module from the module data map.
+
+ m_moduleList.remove(module);
+
+ // Remove exports from package maps.
+ ICapability[] caps = module.getDefinition().getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ // Get package name.
+ String pkgName = (String)
+ caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
+ // Remove from "unresolved" package map.
+ IModule[] modules = (IModule[]) m_unresolvedPkgIndexMap.get(pkgName);
+ if (modules != null)
+ {
+ modules = removeModuleFromArray(modules, module);
+ m_unresolvedPkgIndexMap.put(pkgName, modules);
+ }
+
+ // Remove from "resolved" package map.
+ modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
+ if (modules != null)
+ {
+ modules = removeModuleFromArray(modules, module);
+ m_resolvedPkgIndexMap.put(pkgName, modules);
+ }
+ }
+ }
+
+ // Set fragments to null, which will remove the module from all
+ // of its dependent fragment modules.
+ try
+ {
+ ((ModuleImpl) module).attachFragments(null);
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Error detaching fragments.", ex);
+ }
+ // Set wires to null, which will remove the module from all
+ // of its dependent modules.
+ ((ModuleImpl) module).setWires(null);
+ // Remove the module from the "resolved" map.
+// TODO: RB - Maybe this can be merged with ModuleData.
+ m_resolvedCapMap.remove(module);
+ // Finally, remove module data.
+ m_moduleDataMap.remove(module);
+ }
+
+ private void dumpPackageIndexMap(Map pkgIndexMap)
+ {
+ for (Iterator i = pkgIndexMap.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ IModule[] modules = (IModule[]) entry.getValue();
+ if ((modules != null) && (modules.length > 0))
+ {
+ if (!((modules.length == 1) && modules[0].getId().equals("0")))
+ {
+ System.out.println(" " + entry.getKey());
+ for (int j = 0; j < modules.length; j++)
+ {
+ System.out.println(" " + modules[j]);
+ }
+ }
+ }
+ }
+ }
+
+ public synchronized IModule[] getModules()
+ {
+ return (IModule[]) m_moduleList.toArray(new IModule[m_moduleList.size()]);
+ }
+
+ public String getBundleSymbolicName(IModule module)
+ {
+ ICapability[] caps = module.getDefinition().getCapabilities();
+ for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+ {
+ if (caps[capIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+ {
+ return (String)
+ caps[capIdx].getProperties().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+ }
+ }
+ return null;
+ }
+
+// TODO: FRAGMENT - Not very efficient.
+ private static Version getBundleVersion(IModule module)
+ {
+ ICapability[] caps = module.getDefinition().getCapabilities();
+ for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+ {
+ if (caps[capIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
+ {
+ return (Version)
+ caps[capIdx].getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+ }
+ }
+ return Version.emptyVersion;
+ }
+
+ public synchronized boolean isResolved(IModule module)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data != null)
+ {
+ return data.m_resolved;
+ }
+ return false;
+ }
+
+ public synchronized void setResolved(IModule module, boolean b)
+ {
+ ModuleData data = (ModuleData) m_moduleDataMap.get(module);
+ if (data == null)
+ {
+ data = new ModuleData(module);
+ m_moduleDataMap.put(module, data);
+ }
+ data.m_resolved = b;
+
+ if (data.m_resolved)
+ {
+ // At this point, we need to remove all of the resolved module's
+ // capabilities from the "unresolved" package map and put them in
+ // in the "resolved" package map, with the exception of any
+ // package exports that are also imported. In that case we need
+ // to make sure that the import actually points to the resolved
+ // module and not another module. If it points to another module
+ // then the capability should be ignored, since the framework
+ // decided to honor the import and discard the export.
+ ICapability[] caps = module.getDefinition().getCapabilities();
+
+ // First remove all existing capabilities from the "unresolved" map.
+ for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+ {
+ if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ // Get package name.
+ String pkgName = (String)
+ caps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
+ // Remove the module's capability for the package.
+ m_unresolvedPkgIndexMap.put(
+ pkgName,
+ removeModuleFromArray(
+ (IModule[]) m_unresolvedPkgIndexMap.get(pkgName),
+ module));
+ }
+ }
+
+ // Next create a copy of the module's capabilities so we can
+ // null out any capabilities that should be ignored.
+ ICapability[] capsCopy = (caps == null) ? null : new ICapability[caps.length];
+ if (capsCopy != null)
+ {
+ System.arraycopy(caps, 0, capsCopy, 0, caps.length);
+ }
+ // Loop through the module's capabilities to determine which ones
+ // can be ignored by seeing which ones satifies the wire requirements.
+// TODO: RB - Bug here because a requirement for a package need not overlap the
+// capability for that package and this assumes it does. This might
+// require us to introduce the notion of a substitutable capability.
+ IWire[] wires = module.getWires();
+ for (int capIdx = 0; (capsCopy != null) && (capIdx < capsCopy.length); capIdx++)
+ {
+ // Loop through all wires to see if the current capability
+ // satisfies any of the wire requirements.
+ for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
+ {
+ // If the wire requirement is satisfied by the current capability,
+ // then check to see if the wire is to the module itself. If it
+ // is to another module, then null the current capability since
+ // it was both providing and requiring the same capability and
+ // the resolve process chose to import rather than provide that
+ // capability, therefore we should ignore it.
+ if (wires[wireIdx].getRequirement().isSatisfied(capsCopy[capIdx]))
+ {
+ if (!wires[wireIdx].getExporter().equals(module))
+ {
+ capsCopy[capIdx] = null;
+ }
+ break;
+ }
+ }
+ }
+
+ // Now loop through all capabilities and add them to the "resolved"
+ // capability and package index maps, ignoring any that were nulled out.
+ for (int capIdx = 0; (capsCopy != null) && (capIdx < capsCopy.length); capIdx++)
+ {
+ if (capsCopy[capIdx] != null)
+ {
+ ICapability[] resolvedCaps = (ICapability[]) m_resolvedCapMap.get(module);
+ resolvedCaps = addCapabilityToArray(resolvedCaps, capsCopy[capIdx]);
+ m_resolvedCapMap.put(module, resolvedCaps);
+
+ // If the capability is a package, then add the exporter module
+ // of the wire to the "resolved" package index and remove it
+ // from the "unresolved" package index.
+ if (capsCopy[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ // Add to "resolved" package index.
+ indexPackageCapability(
+ m_resolvedPkgIndexMap,
+ module,
+ capsCopy[capIdx]);
+ }
+ }
+ }
+ }
+
+System.out.println("UNRESOLVED PACKAGES:");
+dumpPackageIndexMap(m_unresolvedPkgIndexMap);
+System.out.println("RESOLVED PACKAGES:");
+dumpPackageIndexMap(m_resolvedPkgIndexMap);
+ }
+
+ // TODO: FRAGMENT - Not very efficient.
+ public synchronized List getPotentialHosts(IModule fragment)
+ {
+ List hostList = new ArrayList();
+
+ IRequirement[] reqs = fragment.getDefinition().getRequirements();
+ IRequirement hostReq = null;
+ for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+ {
+ if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+ {
+ hostReq = reqs[reqIdx];
+ break;
+ }
+ }
+
+ IModule[] modules = getModules();
+ for (int modIdx = 0; (hostReq != null) && (modIdx < modules.length); modIdx++)
+ {
+ if (!fragment.equals(modules[modIdx]) && !isResolved(modules[modIdx]))
+ {
+ ICapability[] caps = modules[modIdx].getDefinition().getCapabilities();
+ for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
+ {
+ if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
+ && hostReq.isSatisfied(caps[capIdx])
+ && !modules[modIdx].isStale())
+ {
+ hostList.add(modules[modIdx]);
+ break;
+ }
+ }
+ }
+ }
+
+ return hostList;
+ }
+
+// TODO: FRAGMENT - Not very efficient.
+ public synchronized Map getPotentialFragments(IModule host)
+ {
+// TODO: FRAGMENT - This should check to make sure that the host allows fragments.
+ Map fragmentMap = new HashMap();
+
+ ICapability[] caps = host.getDefinition().getCapabilities();
+ ICapability bundleCap = null;
+ for (int capIdx = 0; capIdx < caps.length; capIdx++)
+ {
+ if (caps[capIdx].getNamespace().equals(ICapability.HOST_NAMESPACE))
+ {
+ bundleCap = caps[capIdx];
+ break;
+ }
+ }
+
+ IModule[] modules = getModules();
+ for (int modIdx = 0; (bundleCap != null) && (modIdx < modules.length); modIdx++)
+ {
+ if (!host.equals(modules[modIdx]))
+ {
+ IRequirement[] reqs = modules[modIdx].getDefinition().getRequirements();
+ for (int reqIdx = 0; (reqs != null) && (reqIdx < reqs.length); reqIdx++)
+ {
+ if (reqs[reqIdx].getNamespace().equals(ICapability.HOST_NAMESPACE)
+ && reqs[reqIdx].isSatisfied(bundleCap)
+ && !modules[modIdx].isStale())
+ {
+ indexFragment(fragmentMap, modules[modIdx]);
+ break;
+ }
+ }
+ }
+ }
+
+ return fragmentMap;
+ }
+
+ public synchronized PackageSource[] getResolvedCandidates(IRequirement req)
+ {
+ // Synchronized on the module manager to make sure that no
+ // modules are added, removed, or resolved.
+ PackageSource[] candidates = m_emptySources;
+ if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
+ && (((Requirement) req).getPackageName() != null))
+ {
+ String pkgName = ((Requirement) req).getPackageName();
+ IModule[] modules = (IModule[]) m_resolvedPkgIndexMap.get(pkgName);
+
+ for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+ {
+ ICapability resolvedCap = Util.getSatisfyingCapability(modules[modIdx], req);
+ if (resolvedCap != null)
+ {
+// TODO: RB - Is this permission check correct.
+ if ((System.getSecurityManager() != null) &&
+ !((BundleProtectionDomain) modules[modIdx].getContentLoader().getSecurityContext()).impliesDirect(
+ new PackagePermission(pkgName,
+ PackagePermission.EXPORT)))
+ {
+ m_logger.log(Logger.LOG_DEBUG,
+ "PackagePermission.EXPORT denied for "
+ + pkgName
+ + "from " + modules[modIdx].getId());
+ }
+ else
+ {
+ PackageSource[] tmp = new PackageSource[candidates.length + 1];
+ System.arraycopy(candidates, 0, tmp, 0, candidates.length);
+ tmp[candidates.length] =
+ new PackageSource(modules[modIdx], resolvedCap);
+ candidates = tmp;
+ }
+ }
+ }
+ }
+ else
+ {
+ Iterator i = m_resolvedCapMap.entrySet().iterator();
+ while (i.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ IModule module = (IModule) entry.getKey();
+ ICapability[] resolvedCaps = (ICapability[]) entry.getValue();
+ for (int capIdx = 0; capIdx < resolvedCaps.length; capIdx++)
+ {
+ if (req.isSatisfied(resolvedCaps[capIdx]))
+ {
+// TODO: RB - Is this permission check correct.
+ if (resolvedCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+ (System.getSecurityManager() != null) &&
+ !((BundleProtectionDomain) module.getContentLoader().getSecurityContext()).impliesDirect(
+ new PackagePermission(
+ (String) resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY),
+ PackagePermission.EXPORT)))
+ {
+ m_logger.log(Logger.LOG_DEBUG,
+ "PackagePermission.EXPORT denied for "
+ + resolvedCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY)
+ + "from " + module.getId());
+ }
+ else
+ {
+ PackageSource[] tmp = new PackageSource[candidates.length + 1];
+ System.arraycopy(candidates, 0, tmp, 0, candidates.length);
+ tmp[candidates.length] = new PackageSource(module, resolvedCaps[capIdx]);
+ candidates = tmp;
+ }
+ }
+ }
+ }
+ }
+ Arrays.sort(candidates);
+ return candidates;
+ }
+
+ public synchronized PackageSource[] getUnresolvedCandidates(IRequirement req)
+ {
+ // Get all modules.
+ IModule[] modules = null;
+ if (req.getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+ (((Requirement) req).getPackageName() != null))
+ {
+ modules = (IModule[]) m_unresolvedPkgIndexMap.get(((Requirement) req).getPackageName());
+ }
+ else
+ {
+ modules = getModules();
+ }
+
+ // Create list of compatible providers.
+ PackageSource[] candidates = m_emptySources;
+ for (int modIdx = 0; (modules != null) && (modIdx < modules.length); modIdx++)
+ {
+ // Get the module's export package for the target package.
+ ICapability cap = Util.getSatisfyingCapability(modules[modIdx], req);
+ // If compatible and it is not currently resolved, then add
+ // the unresolved candidate to the list.
+ if ((cap != null) && !isResolved(modules[modIdx]))
+ {
+ PackageSource[] tmp = new PackageSource[candidates.length + 1];
+ System.arraycopy(candidates, 0, tmp, 0, candidates.length);
+ tmp[candidates.length] = new PackageSource(modules[modIdx], cap);
+ candidates = tmp;
+ }
+ }
+ Arrays.sort(candidates);
+ return candidates;
+ }
+
+ //
+ // Utility methods.
+ //
+
+ private void indexPackageCapability(Map map, IModule module, ICapability capability)
+ {
+ if (capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ String pkgName = (String)
+ capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
+ IModule[] modules = (IModule[]) map.get(pkgName);
+
+ // We want to add the module into the list of 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
+ {
+ Version version = (Version)
+ capability.getProperties().get(ICapability.VERSION_PROPERTY);
+ Version middleVersion = null;
+ int top = 0, bottom = modules.length - 1, middle = 0;
+ while (top <= bottom)
+ {
+ middle = (bottom - top) / 2 + top;
+ middleVersion = (Version)
+ getExportPackageCapability(
+ modules[middle], pkgName)
+ .getProperties()
+ .get(ICapability.VERSION_PROPERTY);
+ // Sort in reverse version order.
+ int cmp = middleVersion.compareTo(version);
+ 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;
+ }
+ }
+
+ // Ignore duplicates.
+ if ((top >= modules.length) || (modules[top] != module))
+ {
+ 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;
+ }
+ }
+
+ map.put(pkgName, modules);
+ }
+ }
+
+ private void indexFragment(Map map, IModule module)
+ {
+ String symName = getBundleSymbolicName(module);
+ IModule[] modules = (IModule[]) map.get(symName);
+
+ // We want to add the fragment into the list of matching
+ // fragments in sorted order (descending version and
+ // ascending bundle identifier). Insert using a simple
+ // binary search algorithm.
+ if (modules == null)
+ {
+ modules = new IModule[] { module };
+ }
+ else
+ {
+ Version version = getBundleVersion(module);
+ Version middleVersion = null;
+ int top = 0, bottom = modules.length - 1, middle = 0;
+ while (top <= bottom)
+ {
+ middle = (bottom - top) / 2 + top;
+ middleVersion = getBundleVersion(modules[middle]);
+ // Sort in reverse version order.
+ int cmp = middleVersion.compareTo(version);
+ 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;
+ }
+ }
+
+ // Ignore duplicates.
+ if ((top >= modules.length) || (modules[top] != module))
+ {
+ 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;
+ }
+ }
+
+ map.put(symName, modules);
+ }
+
+ private static IModule[] removeModuleFromArray(IModule[] modules, IModule m)
+ {
+ if (modules == null)
+ {
+ return m_emptyModules;
+ }
+
+ int idx = -1;
+ do
+ {
+ 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;
+ }
+ }
+ }
+ while (idx >= 0);
+
+ return modules;
+ }
+
+ public static ICapability getExportPackageCapability(IModule m, String pkgName)
+ {
+ ICapability[] caps = m.getDefinition().getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+ caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
+ {
+ return caps[i];
+ }
+ }
+ return null;
+ }
+
+ private static ICapability[] addCapabilityToArray(ICapability[] caps, ICapability cap)
+ {
+ // Verify that the capability is not already in the array.
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].equals(cap))
+ {
+ return caps;
+ }
+ }
+
+ if (caps != null)
+ {
+ ICapability[] newCaps = new ICapability[caps.length + 1];
+ System.arraycopy(caps, 0, newCaps, 0, caps.length);
+ newCaps[caps.length] = cap;
+ caps = newCaps;
+ }
+ else
+ {
+ caps = new ICapability[] { cap };
+ }
+
+ return caps;
+ }
+ //
+ // Simple utility classes.
+ //
+
+ private static class ModuleData
+ {
+ public IModule m_module = null;
+ public boolean m_resolved = false;
+ public ModuleData(IModule module)
+ {
+ m_module = module;
+ }
+ }
+}
\ No newline at end of file
Added: felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java?rev=729083&view=auto
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java (added)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/PackageSource.java Tue Dec 23 12:07:49 2008
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.Util;
+import org.apache.felix.framework.util.manifestparser.Capability;
+import org.apache.felix.moduleloader.ICapability;
+import org.apache.felix.moduleloader.IModule;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * This utility class represents a source for a given package, where
+ * the package is indicated by a particular module and the module's
+ * capability associated with that package. This class also implements
+ * <tt>Comparable</tt> so that two package sources can be compared based
+ * on version and bundle identifiers.
+ */
+public class PackageSource implements Comparable
+{
+ public IModule m_module = null;
+ public ICapability m_capability = null;
+
+ public PackageSource(IModule module, ICapability capability)
+ {
+ super();
+ m_module = module;
+ m_capability = capability;
+ }
+
+ public int compareTo(Object o)
+ {
+ PackageSource ps = (PackageSource) o;
+ Version thisVersion = null;
+ Version version = null;
+ if (m_capability.getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ thisVersion = ((Capability) m_capability).getPackageVersion();
+ version = ((Capability) ps.m_capability).getPackageVersion();
+ }
+ else if (m_capability.getNamespace().equals(ICapability.MODULE_NAMESPACE))
+ {
+ thisVersion = (Version) m_capability.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+ version = (Version) ps.m_capability.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+ }
+ if ((thisVersion != null) && (version != null))
+ {
+ int cmp = thisVersion.compareTo(version);
+ if (cmp < 0)
+ {
+ return 1;
+ }
+ else if (cmp > 0)
+ {
+ return -1;
+ }
+ else
+ {
+ long thisId = Util.getBundleIdFromModuleId(m_module.getId());
+ long id = Util.getBundleIdFromModuleId(ps.m_module.getId());
+ if (thisId < id)
+ {
+ return -1;
+ }
+ else if (thisId > id)
+ {
+ return 1;
+ }
+ return 0;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ public int hashCode()
+ {
+ final int PRIME = 31;
+ int result = 1;
+ result = PRIME * result + ((m_capability == null) ? 0 : m_capability.hashCode());
+ result = PRIME * result + ((m_module == null) ? 0 : m_module.hashCode());
+ return result;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null)
+ {
+ return false;
+ }
+ if (getClass() != o.getClass())
+ {
+ return false;
+ }
+ PackageSource ps = (PackageSource) o;
+ return m_module.equals(ps.m_module) && (m_capability == ps.m_capability);
+ }
+}