[FELIX-4525] Integrate the standalone resolver in the framework
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1667220 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/pom.xml b/framework/pom.xml
index 18f10e3..240fe2f 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -27,8 +27,7 @@
<packaging>bundle</packaging>
<name>Apache Felix Framework</name>
<artifactId>org.apache.felix.framework</artifactId>
- <version>4.7.0-SNAPSHOT</version>
-
+ <version>4.9.0-SNAPSHOT</version>
<properties>
<dollar>$</dollar>
</properties>
@@ -68,7 +67,7 @@
org.osgi.util.tracker,
org.osgi.dto
</Export-Package>
- <Private-Package>org.apache.felix.framework.*</Private-Package>
+ <Private-Package>org.apache.felix.framework.*, org.apache.felix.resolver.*</Private-Package>
<Import-Package>!*</Import-Package>
</instructions>
</configuration>
@@ -131,6 +130,12 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.resolver</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>4.2</version>
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index b9ac3ab..35cf90d 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -1023,6 +1023,11 @@
AdminPermission.LIFECYCLE));
}
+ Map headers = getCurrentLocalizedHeader(Locale.getDefault().toString());
+
+ // Uninstall the bundle.
+ getFramework().uninstallBundle(this);
+
// After a bundle is uninstalled, the spec says getHeaders() should
// return the localized headers for the default locale at the time of
// of uninstall. So, let's clear the existing header cache to throw
@@ -1035,13 +1040,10 @@
{
if (m_uninstalledHeaders == null)
{
- m_uninstalledHeaders = getCurrentLocalizedHeader(Locale.getDefault().toString());
+ m_uninstalledHeaders = headers;
m_cachedHeaders.clear();
}
}
-
- // Uninstall the bundle.
- getFramework().uninstallBundle(this);
}
private static final SecurityManagerEx m_smEx = new SecurityManagerEx();
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
index 01bf4b8..ee5651d 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
@@ -674,6 +674,6 @@
@Override
public String toString()
{
- return m_id;
+ return m_bundle.toString() + "(R " + m_id + ")";
}
}
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index 8e984cd..80858b3 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -44,7 +44,6 @@
import org.apache.felix.framework.cache.Content;
import org.apache.felix.framework.cache.JarContent;
import org.apache.felix.framework.capabilityset.SimpleFilter;
-import org.apache.felix.framework.resolver.ResolveException;
import org.apache.felix.framework.resolver.ResourceNotFoundException;
import org.apache.felix.framework.util.CompoundEnumeration;
import org.apache.felix.framework.util.FelixConstants;
@@ -75,6 +74,7 @@
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Wire;
+import org.osgi.service.resolver.ResolutionException;
public class BundleWiringImpl implements BundleWiring
{
@@ -1210,7 +1210,7 @@
{
provider = m_resolver.resolve(m_revision, pkgName);
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
// Ignore this since it is likely normal.
}
@@ -1635,7 +1635,7 @@
{
provider = m_resolver.resolve(m_revision, pkgName);
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
// Ignore this since it is likely normal.
}
@@ -2810,7 +2810,7 @@
}
String exporter = (exporters.isEmpty())
- ? null : exporters.iterator().next().getRevision().getBundle().toString();
+ ? null : exporters.iterator().next().toString();
StringBuffer sb = new StringBuffer("*** Class '");
sb.append(name);
@@ -2855,7 +2855,7 @@
// Ignore
}
- String exporter = exports.iterator().next().getRevision().getBundle().toString();
+ String exporter = exports.iterator().next().toString();
StringBuffer sb = new StringBuffer("*** Class '");
sb.append(name);
diff --git a/framework/src/main/java/org/apache/felix/framework/DTOFactory.java b/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
index e3cb64f..99cb8e7 100644
--- a/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
+++ b/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
@@ -313,10 +313,6 @@
private static ServiceReferenceDTO[] createServiceReferenceDTOArray(Bundle bundle)
{
- BundleContext ctx = bundle.getBundleContext();
- if (ctx == null)
- return null;
-
ServiceReference<?>[] svcs = bundle.getRegisteredServices();
if (svcs == null)
return new ServiceReferenceDTO[0];
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index c6b305a..d02d27a 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -57,7 +57,6 @@
import org.apache.felix.framework.capabilityset.CapabilitySet;
import org.apache.felix.framework.capabilityset.SimpleFilter;
import org.apache.felix.framework.ext.SecurityProvider;
-import org.apache.felix.framework.resolver.ResolveException;
import org.apache.felix.framework.util.EventDispatcher;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.ListenerInfo;
@@ -102,6 +101,7 @@
import org.osgi.framework.wiring.FrameworkWiring;
import org.osgi.resource.Requirement;
import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.resolver.ResolutionException;
public class Felix extends BundleImpl implements Framework
{
@@ -412,8 +412,16 @@
// Create default bundle stream handler.
m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
+ // Create service registry.
+ m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() {
+ public void serviceChanged(ServiceEvent event, Dictionary oldProps)
+ {
+ fireServiceEvent(event, oldProps);
+ }
+ });
+
// Create a resolver and its state.
- m_resolver = new StatefulResolver(this);
+ m_resolver = new StatefulResolver(this, m_registry);
// Create the extension manager, which we will use as the
// revision for the system bundle.
@@ -429,14 +437,6 @@
throw new RuntimeException(ex.getMessage());
}
- // Create service registry.
- m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() {
- public void serviceChanged(ServiceEvent event, Dictionary oldProps)
- {
- fireServiceEvent(event, oldProps);
- }
- });
-
// Create event dispatcher.
m_dispatcher = new EventDispatcher(m_logger, m_registry);
@@ -734,12 +734,12 @@
Collections.singleton(adapt(BundleRevision.class)),
Collections.EMPTY_SET);
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
// This should never happen.
throw new BundleException(
"Unresolved constraint in System Bundle:"
- + ex.getRequirement());
+ + ex.getUnresolvedRequirements());
}
// Reload the cached bundles before creating and starting the
@@ -833,6 +833,7 @@
}
// Start services
+ m_resolver.start();
m_fwkWiring.start();
m_fwkStartLevel.start();
@@ -4062,7 +4063,7 @@
}
}
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
result = false;
}
@@ -4087,19 +4088,11 @@
{
m_resolver.resolve(Collections.singleton(revision), Collections.EMPTY_SET);
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
- if (ex.getRevision() != null)
- {
- Bundle b = ex.getRevision().getBundle();
- throw new BundleException(
- "Unresolved constraint in bundle "
- + b + ": " + ex.getMessage(), BundleException.RESOLVE_ERROR);
- }
- else
- {
- throw new BundleException(ex.getMessage(), BundleException.RESOLVE_ERROR);
- }
+ throw new BundleException(ex.getMessage() +
+ " Unresolved requirements: " + ex.getUnresolvedRequirements(),
+ BundleException.RESOLVE_ERROR);
}
}
diff --git a/framework/src/main/java/org/apache/felix/framework/Logger.java b/framework/src/main/java/org/apache/felix/framework/Logger.java
index 6e05d4f..42f3b13 100644
--- a/framework/src/main/java/org/apache/felix/framework/Logger.java
+++ b/framework/src/main/java/org/apache/felix/framework/Logger.java
@@ -20,7 +20,14 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import org.osgi.framework.*;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
/**
* <p>
@@ -41,14 +48,9 @@
* the log service's method to avoid a dependency on the log interface.
* </p>
**/
-public class Logger implements ServiceListener
+public class Logger extends org.apache.felix.resolver.Logger implements ServiceListener
{
- public static final int LOG_ERROR = 1;
- public static final int LOG_WARNING = 2;
- public static final int LOG_INFO = 3;
- public static final int LOG_DEBUG = 4;
-
- private int m_logLevel = 1;
+ // TODO see if this class can be cleaned up a little more
private BundleContext m_context = null;
private final static int LOGGER_OBJECT_IDX = 0;
@@ -58,42 +60,23 @@
public Logger()
{
- }
-
- public final synchronized void setLogLevel(int i)
- {
- m_logLevel = i;
- }
-
- public final synchronized int getLogLevel()
- {
- return m_logLevel;
+ super(LOG_ERROR);
}
protected void setSystemBundleContext(BundleContext context)
{
// TODO: Find a way to log to a log service inside the framework.
// The issue is that we log messages while holding framework
- // internal locks -- hence, when a log service calls back into
- // the framework (e.g., by loading a class) we might deadlock.
+ // internal locks -- hence, when a log service calls back into
+ // the framework (e.g., by loading a class) we might deadlock.
// One instance of this problem is tracked in FELIX-536.
// For now we just disable logging to log services inside the
- // framework.
+ // framework.
// m_context = context;
// startListeningForLogService();
}
- public final void log(int level, String msg)
- {
- _log(null, null, level, msg, null);
- }
-
- public final void log(int level, String msg, Throwable throwable)
- {
- _log(null, null, level, msg, throwable);
- }
-
public final void log(ServiceReference sr, int level, String msg)
{
_log(null, sr, level, msg, null);
@@ -168,7 +151,7 @@
// more conservative locking here, but let's be optimistic.
Object[] logger = m_logger;
- if (m_logLevel >= level)
+ if (getLogLevel() >= level)
{
// Use the log service if available.
if (logger != null)
diff --git a/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java b/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
index 270da4f..bca43b4 100644
--- a/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
@@ -26,29 +26,32 @@
import org.apache.felix.framework.StatefulResolver.ResolverHookRecord;
import org.apache.felix.framework.resolver.CandidateComparator;
-import org.apache.felix.framework.resolver.HostedCapability;
-import org.apache.felix.framework.resolver.ResolveContext;
-import org.apache.felix.framework.resolver.ResolveException;
+import org.apache.felix.resolver.FelixResolveContext;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wiring;
+import org.osgi.service.resolver.HostedCapability;
+import org.osgi.service.resolver.ResolveContext;
/**
*
* @author rickhall
*/
-public class ResolveContextImpl extends ResolveContext
+public class ResolveContextImpl extends ResolveContext implements FelixResolveContext
{
private final StatefulResolver m_state;
- private final Map<BundleRevision, BundleWiring> m_wirings;
+ private final Map<Resource, Wiring> m_wirings;
private final ResolverHookRecord m_resolverHookrecord;
private final Collection<BundleRevision> m_mandatory;
private final Collection<BundleRevision> m_optional;
private final Collection<BundleRevision> m_ondemand;
ResolveContextImpl(
- StatefulResolver state, Map<BundleRevision, BundleWiring> wirings,
+ StatefulResolver state, Map<Resource, Wiring> wirings,
ResolverHookRecord resolverHookRecord, Collection<BundleRevision> mandatory,
Collection<BundleRevision> optional, Collection<BundleRevision> ondemand)
{
@@ -61,30 +64,41 @@
}
@Override
- public Collection<BundleRevision> getMandatoryRevisions()
+ public Collection<Resource> getMandatoryResources()
{
- return new ArrayList<BundleRevision>(m_mandatory);
+ return new ArrayList<Resource>(m_mandatory);
}
@Override
- public Collection<BundleRevision> getOptionalRevisions()
+ public Collection<Resource> getOptionalResources()
{
- return new ArrayList<BundleRevision>(m_optional);
+ return new ArrayList<Resource>(m_optional);
}
- public Collection<BundleRevision> getOndemandRevisions()
+ public Collection<Resource> getOndemandResources(Resource host)
{
- return new ArrayList<BundleRevision>(m_ondemand);
+ return new ArrayList<Resource>(m_ondemand);
}
@Override
- public List<BundleCapability> findProviders(BundleRequirement br, boolean obeyMandatory)
+ public List<Capability> findProviders(Requirement br)
{
- return m_state.findProvidersInternal(m_resolverHookrecord, br, obeyMandatory, true);
+ if (!(br instanceof BundleRequirement))
+ throw new IllegalStateException("Expected a BundleRequirement");
+
+ List<BundleCapability> result = m_state.findProvidersInternal(
+ m_resolverHookrecord, br, true, true);
+
+ // Casting the result to a List of Capability.
+ // TODO Can we do this without the strang double-cast?
+ @SuppressWarnings("unchecked")
+ List<Capability> caps =
+ (List<Capability>) (List<? extends Capability>) result;
+ return caps;
}
@Override
- public int insertHostedCapability(List<BundleCapability> caps, HostedCapability hc)
+ public int insertHostedCapability(List<Capability> caps, HostedCapability hc)
{
int idx = Collections.binarySearch(caps, hc, new CandidateComparator());
if (idx < 0)
@@ -96,19 +110,14 @@
}
@Override
- public boolean isEffective(BundleRequirement br)
+ public boolean isEffective(Requirement br)
{
return m_state.isEffective(br);
}
@Override
- public Map<BundleRevision, BundleWiring> getWirings()
+ public Map<Resource, Wiring> getWirings()
{
return m_wirings;
}
-
- public void checkNativeLibraries(BundleRevision rev) throws ResolveException
- {
- m_state.checkNativeLibraries(rev);
- }
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
index dec5a0c..191a65f 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -42,7 +42,6 @@
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
-import org.osgi.framework.wiring.BundleCapability;
public class ServiceRegistry
{
diff --git a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index 11464a1..3ec6c76 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -36,14 +36,12 @@
import org.apache.felix.framework.capabilityset.SimpleFilter;
import org.apache.felix.framework.resolver.CandidateComparator;
import org.apache.felix.framework.resolver.ResolveException;
-import org.apache.felix.framework.resolver.Resolver;
-import org.apache.felix.framework.resolver.ResolverImpl;
-import org.apache.felix.framework.resolver.ResolverWire;
import org.apache.felix.framework.util.ShrinkableCollection;
import org.apache.felix.framework.util.Util;
import org.apache.felix.framework.util.manifestparser.NativeLibrary;
import org.apache.felix.framework.wiring.BundleRequirementImpl;
import org.apache.felix.framework.wiring.BundleWireImpl;
+import org.apache.felix.resolver.ResolverImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
@@ -60,12 +58,19 @@
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.resource.Requirement;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+import org.osgi.resource.Wiring;
+import org.osgi.service.resolver.ResolutionException;
+import org.osgi.service.resolver.Resolver;
class StatefulResolver
{
private final Logger m_logger;
private final Felix m_felix;
- private final Resolver m_resolver;
+ private final ServiceRegistry m_registry;
+ private final ResolverImpl m_resolver;
private boolean m_isResolving = false;
// Set of all revisions.
@@ -83,9 +88,10 @@
// Parsed framework environments
private final Set<String> m_fwkExecEnvSet;
- StatefulResolver(Felix felix)
+ StatefulResolver(Felix felix, ServiceRegistry registry)
{
m_felix = felix;
+ m_registry = registry;
m_logger = m_felix.getLogger();
m_resolver = new ResolverImpl(m_logger);
@@ -113,6 +119,14 @@
m_capSets.put(BundleRevision.HOST_NAMESPACE, new CapabilitySet(indices, true));
}
+ void start()
+ {
+ m_registry.registerService(m_felix._getBundleContext(),
+ new String[] { Resolver.class.getName() },
+ m_resolver,
+ null);
+ }
+
synchronized void addRevision(BundleRevision br)
{
// Always attempt to remove the revision, since
@@ -165,7 +179,7 @@
}
}
- boolean isEffective(BundleRequirement req)
+ boolean isEffective(Requirement req)
{
String effective = req.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
return ((effective == null) || effective.equals(Constants.EFFECTIVE_RESOLVE));
@@ -212,24 +226,29 @@
}
// Find the matching candidates.
- Set<BundleCapability> matches = capSet.match(sf, obeyMandatory);
+ Set<Capability> matches = capSet.match(sf, obeyMandatory);
// Filter matching candidates.
- for (BundleCapability cap : matches)
+ for (Capability cap : matches)
{
+ if (!(cap instanceof BundleCapability))
+ continue;
+
+ BundleCapability bcap = (BundleCapability) cap;
+
// Filter according to security.
- if (invokeHooksAndSecurity && filteredBySecurity((BundleRequirement)req, cap))
+ if (invokeHooksAndSecurity && filteredBySecurity((BundleRequirement)req, bcap))
{
continue;
}
// Filter already resolved hosts, since we don't support
// dynamic attachment of fragments.
if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE)
- && (cap.getRevision().getWiring() != null))
+ && (bcap.getRevision().getWiring() != null))
{
continue;
}
- result.add(cap);
+ result.add(bcap);
}
}
@@ -341,7 +360,7 @@
void resolve(
Set<BundleRevision> mandatory,
Set<BundleRevision> optional)
- throws ResolveException, BundleException
+ throws ResolutionException, BundleException
{
// Acquire global lock.
boolean locked = m_felix.acquireGlobalLock();
@@ -360,7 +379,7 @@
}
m_isResolving = true;
- Map<BundleRevision, List<ResolverWire>> wireMap = null;
+ Map<Resource, List<Wire>> wireMap = null;
try
{
// Make our own copy of revisions.
@@ -405,7 +424,7 @@
// Catch any resolve exception to rethrow later because
// we may need to call end() on resolver hooks.
- ResolveException rethrow = null;
+ ResolutionException rethrow = null;
try
{
// Resolve the revision.
@@ -418,7 +437,7 @@
optional,
getFragments()));
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
rethrow = ex;
}
@@ -447,7 +466,7 @@
}
BundleRevision resolve(BundleRevision revision, String pkgName)
- throws ResolveException, BundleException
+ throws ResolutionException, BundleException
{
BundleRevision provider = null;
@@ -475,7 +494,7 @@
}
m_isResolving = true;
- Map<BundleRevision, List<ResolverWire>> wireMap = null;
+ Map<Resource, List<Wire>> wireMap = null;
try
{
// Double check to make sure that someone hasn't beaten us to
@@ -496,20 +515,74 @@
// Catch any resolve exception to rethrow later because
// we may need to call end() on resolver hooks.
- ResolveException rethrow = null;
+ ResolutionException rethrow = null;
try
{
+ List<BundleRequirement> dynamics =
+ Util.getDynamicRequirements(revision.getWiring().getRequirements(null));
+
+ // Loop through the importer's dynamic requirements to determine if
+ // there is a matching one for the package from which we want to
+ // load a class.
+ Map<String, Object> attrs = Collections.singletonMap(
+ BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
+ BundleRequirementImpl req = new BundleRequirementImpl(
+ revision,
+ BundleRevision.PACKAGE_NAMESPACE,
+ Collections.EMPTY_MAP,
+ attrs);
+ List<BundleCapability> candidates = findProvidersInternal(record, req, false, true);
+
+ // Try to find a dynamic requirement that matches the capabilities.
+ BundleRequirementImpl dynReq = null;
+ for (int dynIdx = 0;
+ (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size());
+ dynIdx++)
+ {
+ for (Iterator<BundleCapability> itCand = candidates.iterator();
+ (dynReq == null) && itCand.hasNext(); )
+ {
+ Capability cap = itCand.next();
+ if (CapabilitySet.matches(
+ cap,
+ ((BundleRequirementImpl) dynamics.get(dynIdx)).getFilter()))
+ {
+ dynReq = (BundleRequirementImpl) dynamics.get(dynIdx);
+ }
+ }
+ }
+
+ // If we found a matching dynamic requirement, then filter out
+ // any candidates that do not match it.
+ if (dynReq != null)
+ {
+ for (Iterator<BundleCapability> itCand = candidates.iterator();
+ itCand.hasNext(); )
+ {
+ Capability cap = itCand.next();
+ if (!CapabilitySet.matches(
+ cap, dynReq.getFilter()))
+ {
+ itCand.remove();
+ }
+ }
+ }
+ else
+ {
+ candidates.clear();
+ }
+
wireMap = m_resolver.resolve(
new ResolveContextImpl(
this,
getWirings(),
record,
- Collections.EMPTY_LIST,
- Collections.EMPTY_LIST,
+ Collections.<BundleRevision>emptyList(),
+ Collections.<BundleRevision>emptyList(),
getFragments()),
- revision, pkgName);
+ revision, dynReq, new ArrayList<Capability>(candidates));
}
- catch (ResolveException ex)
+ catch (ResolutionException ex)
{
rethrow = ex;
}
@@ -525,8 +598,8 @@
if ((wireMap != null) && wireMap.containsKey(revision))
{
- List<ResolverWire> dynamicWires = wireMap.remove(revision);
- ResolverWire dynamicWire = dynamicWires.get(0);
+ List<Wire> dynamicWires = wireMap.remove(revision);
+ Wire dynamicWire = dynamicWires.get(0);
// Mark all revisions as resolved.
markResolvedRevisions(wireMap);
@@ -534,22 +607,35 @@
// Dynamically add new wire to importing revision.
if (dynamicWire != null)
{
- BundleWire bw = new BundleWireImpl(
- dynamicWire.getRequirer(),
- dynamicWire.getRequirement(),
- dynamicWire.getProvider(),
- dynamicWire.getCapability());
+ // TODO is a rw already a BundleWire?
+ // TODO can we optimize this?
+ if (dynamicWire.getRequirer() instanceof BundleRevision &&
+ dynamicWire.getRequirement() instanceof BundleRequirement &&
+ dynamicWire.getProvider() instanceof BundleRevision &&
+ dynamicWire.getCapability() instanceof BundleCapability)
+ {
+ BundleRevision dwRequirer = (BundleRevision) dynamicWire.getRequirer();
+ BundleRequirement dwRequirement = (BundleRequirement) dynamicWire.getRequirement();
+ BundleRevision dwProvider = (BundleRevision) dynamicWire.getProvider();
+ BundleCapability dwCapability = (BundleCapability) dynamicWire.getCapability();
- m_felix.getDependencies().addDependent(bw);
+ BundleWire bw = new BundleWireImpl(
+ dwRequirer,
+ dwRequirement,
+ dwProvider,
+ dwCapability);
- ((BundleWiringImpl) revision.getWiring()).addDynamicWire(bw);
+ m_felix.getDependencies().addDependent(bw);
- m_felix.getLogger().log(
- Logger.LOG_DEBUG,
- "DYNAMIC WIRE: " + dynamicWire);
+ ((BundleWiringImpl) revision.getWiring()).addDynamicWire(bw);
- provider = ((BundleWiringImpl) revision.getWiring())
- .getImportedPackageSource(pkgName);
+ m_felix.getLogger().log(
+ Logger.LOG_DEBUG,
+ "DYNAMIC WIRE: " + dynamicWire);
+
+ provider = ((BundleWiringImpl) revision.getWiring())
+ .getImportedPackageSource(pkgName);
+ }
}
}
}
@@ -570,7 +656,7 @@
private ResolverHookRecord prepareResolverHooks(
Set<BundleRevision> mandatory, Set<BundleRevision> optional)
- throws BundleException
+ throws BundleException, ResolutionException
{
// This map maps the hook factory service to the actual hook objects. It
// needs to be a map that preserves insertion order to ensure that we call
@@ -829,7 +915,7 @@
for (Iterator<BundleCapability> itCand = candidates.iterator();
(dynReq == null) && itCand.hasNext(); )
{
- BundleCapability cap = itCand.next();
+ Capability cap = itCand.next();
if (CapabilitySet.matches(
cap,
((BundleRequirementImpl) dynamics.get(dynIdx)).getFilter()))
@@ -846,7 +932,7 @@
for (Iterator<BundleCapability> itCand = candidates.iterator();
itCand.hasNext(); )
{
- BundleCapability cap = itCand.next();
+ Capability cap = itCand.next();
if (!CapabilitySet.matches(
cap, dynReq.getFilter()))
{
@@ -862,7 +948,7 @@
return !candidates.isEmpty();
}
- private void markResolvedRevisions(Map<BundleRevision, List<ResolverWire>> wireMap)
+ private void markResolvedRevisions(Map<Resource, List<Wire>> wireMap)
throws ResolveException
{
boolean debugLog = m_felix.getLogger().getLogLevel() >= Logger.LOG_DEBUG;
@@ -878,26 +964,28 @@
{
// First pass: Loop through the wire map to find the host wires
// for any fragments and map a host to all of its fragments.
- Map<BundleRevision, List<BundleRevision>> hosts =
- new HashMap<BundleRevision, List<BundleRevision>>();
- for (Entry<BundleRevision, List<ResolverWire>> entry : wireMap.entrySet())
+ Map<Resource, List<BundleRevision>> hosts =
+ new HashMap<Resource, List<BundleRevision>>();
+ for (Entry<Resource, List<Wire>> entry : wireMap.entrySet())
{
- BundleRevision revision = entry.getKey();
- List<ResolverWire> wires = entry.getValue();
+ Resource revision = entry.getKey();
+ List<Wire> wires = entry.getValue();
if (Util.isFragment(revision))
{
- for (Iterator<ResolverWire> itWires = wires.iterator();
+ for (Iterator<Wire> itWires = wires.iterator();
itWires.hasNext(); )
{
- ResolverWire w = itWires.next();
+ Wire w = itWires.next();
List<BundleRevision> fragments = hosts.get(w.getProvider());
if (fragments == null)
{
fragments = new ArrayList<BundleRevision>();
hosts.put(w.getProvider(), fragments);
}
- fragments.add(w.getRequirer());
+
+ if (w.getRequirer() instanceof BundleRevision)
+ fragments.add((BundleRevision) w.getRequirer());
}
}
}
@@ -911,10 +999,14 @@
// all wirings.
Map<BundleRevision, BundleWiringImpl> wirings =
new HashMap<BundleRevision, BundleWiringImpl>(wireMap.size());
- for (Entry<BundleRevision, List<ResolverWire>> entry : wireMap.entrySet())
+ for (Entry<Resource, List<Wire>> entry : wireMap.entrySet())
{
- BundleRevision revision = entry.getKey();
- List<ResolverWire> resolverWires = entry.getValue();
+ Resource resource = entry.getKey();
+ if (!(resource instanceof BundleRevision))
+ continue;
+
+ BundleRevision revision = (BundleRevision) resource;
+ List<Wire> resolverWires = entry.getValue();
List<BundleWire> bundleWires =
new ArrayList<BundleWire>(resolverWires.size());
@@ -936,13 +1028,28 @@
new HashMap<String, BundleRevision>();
Map<String, List<BundleRevision>> requiredPkgs =
new HashMap<String, List<BundleRevision>>();
- for (ResolverWire rw : resolverWires)
+ for (Wire rw : resolverWires)
{
+ // TODO is a rw already a BundleWire?
+ // TODO can we optimize this?
+ if (!(rw.getRequirer() instanceof BundleRevision))
+ continue;
+ BundleRevision requirer = (BundleRevision) rw.getRequirer();
+ if (!(rw.getRequirement() instanceof BundleRequirement))
+ continue;
+ BundleRequirement requirement = (BundleRequirement) rw.getRequirement();
+ if (!(rw.getProvider() instanceof BundleRevision))
+ continue;
+ BundleRevision provider = (BundleRevision) rw.getProvider();
+ if (!(rw.getCapability() instanceof BundleCapability))
+ continue;
+ BundleCapability capability = (BundleCapability) rw.getCapability();
+
BundleWire bw = new BundleWireImpl(
- rw.getRequirer(),
- rw.getRequirement(),
- rw.getProvider(),
- rw.getCapability());
+ requirer,
+ requirement,
+ provider,
+ capability);
bundleWires.add(bw);
if (Util.isFragment(revision))
@@ -961,19 +1068,19 @@
m_felix.getLogger().log(Logger.LOG_DEBUG, "WIRE: " + rw.toString());
}
- if (rw.getCapability().getNamespace()
+ if (capability.getNamespace()
.equals(BundleRevision.PACKAGE_NAMESPACE))
{
importedPkgs.put(
- (String) rw.getCapability().getAttributes()
+ (String) capability.getAttributes()
.get(BundleRevision.PACKAGE_NAMESPACE),
- rw.getProvider());
+ provider);
}
- else if (rw.getCapability().getNamespace()
+ else if (capability.getNamespace()
.equals(BundleRevision.BUNDLE_NAMESPACE))
{
Set<String> pkgs = calculateExportedAndReexportedPackages(
- rw.getProvider(),
+ provider,
wireMap,
new HashSet<String>(),
new HashSet<BundleRevision>());
@@ -985,7 +1092,7 @@
revs = new ArrayList<BundleRevision>();
requiredPkgs.put(pkg, revs);
}
- revs.add(rw.getProvider());
+ revs.add(provider);
}
}
}
@@ -1110,17 +1217,21 @@
}
}
- private void fireResolvedEvents(Map<BundleRevision, List<ResolverWire>> wireMap)
+ private void fireResolvedEvents(Map<Resource, List<Wire>> wireMap)
{
if (wireMap != null)
{
- Iterator<Entry<BundleRevision, List<ResolverWire>>> iter =
+ Iterator<Entry<Resource, List<Wire>>> iter =
wireMap.entrySet().iterator();
// Iterate over the map to fire necessary RESOLVED events.
while (iter.hasNext())
{
- Entry<BundleRevision, List<ResolverWire>> entry = iter.next();
- BundleRevision revision = entry.getKey();
+ Entry<Resource, List<Wire>> entry = iter.next();
+ Resource resource = entry.getKey();
+ if (!(resource instanceof BundleRevision))
+ continue;
+
+ BundleRevision revision = (BundleRevision) resource;
// Fire RESOLVED events for all fragments.
List<BundleRevision> fragments =
@@ -1137,7 +1248,7 @@
private static Set<String> calculateExportedAndReexportedPackages(
BundleRevision br,
- Map<BundleRevision, List<ResolverWire>> wireMap,
+ Map<Resource, List<Wire>> wireMap,
Set<String> pkgs,
Set<BundleRevision> cycles)
{
@@ -1159,7 +1270,7 @@
// visibility, since we need to include those packages too.
if (br.getWiring() == null)
{
- for (ResolverWire rw : wireMap.get(br))
+ for (Wire rw : wireMap.get(br))
{
if (rw.getCapability().getNamespace().equals(
BundleRevision.BUNDLE_NAMESPACE))
@@ -1169,7 +1280,8 @@
if ((dir != null) && (dir.equals(Constants.VISIBILITY_REEXPORT)))
{
calculateExportedAndReexportedPackages(
- rw.getProvider(),
+ // TODO need to fix the cast
+ (BundleRevision) rw.getProvider(),
wireMap,
pkgs,
cycles);
@@ -1526,9 +1638,9 @@
return unresolved;
}
- private synchronized Map<BundleRevision, BundleWiring> getWirings()
+ private synchronized Map<Resource, Wiring> getWirings()
{
- Map<BundleRevision, BundleWiring> wirings = new HashMap<BundleRevision, BundleWiring>();
+ Map<Resource, Wiring> wirings = new HashMap<Resource, Wiring>();
for (BundleRevision revision : m_revisions)
{
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
index 8f0c605..a64b4ab 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
@@ -39,11 +39,12 @@
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.osgi.framework.Version;
import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.resource.Capability;
public class CapabilitySet
{
private final Map<String, Map<Object, Set<BundleCapability>>> m_indices;
- private final Set<BundleCapability> m_capSet = new HashSet<BundleCapability>();
+ private final Set<Capability> m_capSet = new HashSet<Capability>();
private final static SecureAction m_secureAction = new SecureAction();
public void dump()
@@ -180,17 +181,17 @@
}
}
- public Set<BundleCapability> match(SimpleFilter sf, boolean obeyMandatory)
+ public Set<Capability> match(SimpleFilter sf, boolean obeyMandatory)
{
- Set<BundleCapability> matches = match(m_capSet, sf);
+ Set<Capability> matches = match(m_capSet, sf);
return (obeyMandatory)
? matchMandatory(matches, sf)
: matches;
}
- private Set<BundleCapability> match(Set<BundleCapability> caps, SimpleFilter sf)
+ private Set<Capability> match(Set<Capability> caps, SimpleFilter sf)
{
- Set<BundleCapability> matches = new HashSet<BundleCapability>();
+ Set<Capability> matches = new HashSet<Capability>();
if (sf.getOperation() == SimpleFilter.MATCH_ALL)
{
@@ -247,9 +248,9 @@
}
else
{
- for (Iterator<BundleCapability> it = caps.iterator(); it.hasNext(); )
+ for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
{
- BundleCapability cap = it.next();
+ Capability cap = it.next();
Object lhs = cap.getAttributes().get(sf.getName());
if (lhs != null)
{
@@ -265,12 +266,12 @@
return matches;
}
- public static boolean matches(BundleCapability cap, SimpleFilter sf)
+ public static boolean matches(Capability cap, SimpleFilter sf)
{
return matchesInternal(cap, sf) && matchMandatory(cap, sf);
}
- private static boolean matchesInternal(BundleCapability cap, SimpleFilter sf)
+ private static boolean matchesInternal(Capability cap, SimpleFilter sf)
{
boolean matched = true;
@@ -324,12 +325,12 @@
return matched;
}
- private static Set<BundleCapability> matchMandatory(
- Set<BundleCapability> caps, SimpleFilter sf)
+ private static Set<Capability> matchMandatory(
+ Set<Capability> caps, SimpleFilter sf)
{
- for (Iterator<BundleCapability> it = caps.iterator(); it.hasNext(); )
+ for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
{
- BundleCapability cap = it.next();
+ Capability cap = it.next();
if (!matchMandatory(cap, sf))
{
it.remove();
@@ -338,7 +339,7 @@
return caps;
}
- private static boolean matchMandatory(BundleCapability cap, SimpleFilter sf)
+ private static boolean matchMandatory(Capability cap, SimpleFilter sf)
{
Map<String, Object> attrs = cap.getAttributes();
for (Entry<String, Object> entry : attrs.entrySet())
@@ -468,7 +469,7 @@
return false;
}
case SimpleFilter.APPROX :
- return compareApproximate(((Comparable) lhs), rhs);
+ return compareApproximate(lhs, rhs);
case SimpleFilter.SUBSTRING :
return SimpleFilter.compareSubstring((List<String>) rhs, (String) lhs);
default:
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java b/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
index dccd7ca..a6117f1 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
@@ -19,29 +19,42 @@
package org.apache.felix.framework.resolver;
import java.util.Comparator;
+
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.resource.Capability;
-public class CandidateComparator implements Comparator<BundleCapability>
+public class CandidateComparator implements Comparator<Capability>
{
- public int compare(BundleCapability cap1, BundleCapability cap2)
+ public int compare(Capability cap1, Capability cap2)
{
// First check resolved state, since resolved capabilities have priority
// over unresolved ones. Compare in reverse order since we want to sort
// in descending order.
int c = 0;
- if ((cap1.getRevision().getWiring() != null)
- && (cap2.getRevision().getWiring() == null))
+
+ BundleCapability bcap1 = null;
+ BundleCapability bcap2 = null;
+
+ if (cap1 instanceof BundleCapability &&
+ cap2 instanceof BundleCapability)
{
- c = -1;
- }
- else if ((cap1.getRevision().getWiring() == null)
- && (cap2.getRevision().getWiring() != null))
- {
- c = 1;
+ bcap1 = (BundleCapability) cap1;
+ bcap2 = (BundleCapability) cap2;
+
+ if ((bcap1.getRevision().getWiring() != null)
+ && (bcap2.getRevision().getWiring() == null))
+ {
+ c = -1;
+ }
+ else if ((bcap1.getRevision().getWiring() == null)
+ && (bcap2.getRevision().getWiring() != null))
+ {
+ c = 1;
+ }
}
// Compare revision capabilities.
@@ -82,15 +95,15 @@
}
// Finally, compare bundle identity.
- if (c == 0)
+ if (c == 0 && bcap1 != null && bcap2 != null)
{
- if (cap1.getRevision().getBundle().getBundleId() <
- cap2.getRevision().getBundle().getBundleId())
+ if (bcap1.getRevision().getBundle().getBundleId() <
+ bcap2.getRevision().getBundle().getBundleId())
{
c = -1;
}
- else if (cap1.getRevision().getBundle().getBundleId() >
- cap2.getRevision().getBundle().getBundleId())
+ else if (bcap1.getRevision().getBundle().getBundleId() >
+ bcap2.getRevision().getBundle().getBundleId())
{
c = 1;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java b/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
deleted file mode 100644
index 9f57f95..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.apache.felix.framework.ResolveContextImpl;
-import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-import org.apache.felix.framework.wiring.BundleRequirementImpl;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWire;
-import org.osgi.framework.wiring.BundleWiring;
-
-class Candidates
-{
- public static final int MANDATORY = 0;
- public static final int OPTIONAL = 1;
- public static final int ON_DEMAND = 2;
-
- private final Set<BundleRevision> m_mandatoryRevisions;
- // Maps a capability to requirements that match it.
- private final Map<BundleCapability, Set<BundleRequirement>> m_dependentMap;
- // Maps a requirement to the capability it matches.
- private final Map<BundleRequirement, List<BundleCapability>> m_candidateMap;
- // Maps a bundle revision to its associated wrapped revision; this only happens
- // when a revision being resolved has fragments to attach to it.
- private final Map<BundleRevision, WrappedRevision> m_allWrappedHosts;
- // Map used when populating candidates to hold intermediate and final results.
- private final Map<BundleRevision, Object> m_populateResultCache;
-
- // Flag to signal if fragments are present in the candidate map.
- private boolean m_fragmentsPresent = false;
-
- /**
- * Private copy constructor used by the copy() method.
- * @param dependentMap the capability dependency map.
- * @param candidateMap the requirement candidate map.
- * @param hostFragments the fragment map.
- * @param wrappedHosts the wrapped hosts map.
- **/
- private Candidates(
- Set<BundleRevision> mandatoryRevisions,
- Map<BundleCapability, Set<BundleRequirement>> dependentMap,
- Map<BundleRequirement, List<BundleCapability>> candidateMap,
- Map<BundleRevision, WrappedRevision> wrappedHosts, Map<BundleRevision, Object> populateResultCache,
- boolean fragmentsPresent)
- {
- m_mandatoryRevisions = mandatoryRevisions;
- m_dependentMap = dependentMap;
- m_candidateMap = candidateMap;
- m_allWrappedHosts = wrappedHosts;
- m_populateResultCache = populateResultCache;
- m_fragmentsPresent = fragmentsPresent;
- }
-
- /**
- * Constructs an empty Candidates object.
- **/
- public Candidates()
- {
- m_mandatoryRevisions = new HashSet<BundleRevision>();
- m_dependentMap = new HashMap<BundleCapability, Set<BundleRequirement>>();
- m_candidateMap = new HashMap<BundleRequirement, List<BundleCapability>>();
- m_allWrappedHosts = new HashMap<BundleRevision, WrappedRevision>();
- m_populateResultCache = new HashMap<BundleRevision, Object>();
- }
-
- /**
- * Populates candidates for the specified revision. How a revision is
- * resolved depends on its resolution type as follows:
- * <ul>
- * <li><tt>MANDATORY</tt> - must resolve and failure to do so throws
- * an exception.</li>
- * <li><tt>OPTIONAL</tt> - attempt to resolve, but no exception is thrown
- * if the resolve fails.</li>
- * <li><tt>ON_DEMAND</tt> - only resolve on demand; this only applies to
- * fragments and will only resolve a fragment if its host is already
- * selected as a candidate.</li>
- * </ul>
- * @param state the resolver state used for populating the candidates.
- * @param revision the revision whose candidates should be populated.
- * @param resolution indicates the resolution type.
- */
- public final void populate(
- ResolveContext rc, BundleRevision revision, int resolution)
- {
- // Get the current result cache value, to make sure the revision
- // hasn't already been populated.
- Object cacheValue = m_populateResultCache.get(revision);
- // Has been unsuccessfully populated.
- if (cacheValue instanceof ResolveException)
- {
- return;
- }
- // Has been successfully populated.
- else if (cacheValue instanceof Boolean)
- {
- return;
- }
-
- // We will always attempt to populate fragments, since this is necessary
- // for ondemand attaching of fragment. However, we'll only attempt to
- // populate optional non-fragment revisions if they aren't already
- // resolved.
- boolean isFragment = Util.isFragment(revision);
- if (!isFragment && (revision.getWiring() != null))
- {
- return;
- }
-
- // Always attempt to populate mandatory or optional revisions.
- // However, for on-demand fragments only populate if their host
- // is already populated.
- if ((resolution != ON_DEMAND)
- || (isFragment && populateFragmentOndemand(rc, revision)))
- {
- if (resolution == MANDATORY)
- {
- m_mandatoryRevisions.add(revision);
- }
- try
- {
- // Try to populate candidates for the optional revision.
- populateRevision(rc, revision);
- }
- catch (ResolveException ex)
- {
- // Only throw an exception if resolution is mandatory.
- if (resolution == MANDATORY)
- {
- throw ex;
- }
- }
- }
- }
-
- /**
- * Populates candidates for the specified revision.
- * @param state the resolver state used for populating the candidates.
- * @param revision the revision whose candidates should be populated.
- */
-// TODO: FELIX3 - Modify to not be recursive.
- private void populateRevision(ResolveContext rc, BundleRevision revision)
- {
- // Determine if we've already calculated this revision's candidates.
- // The result cache will have one of three values:
- // 1. A resolve exception if we've already attempted to populate the
- // revision's candidates but were unsuccessful.
- // 2. Boolean.TRUE indicating we've already attempted to populate the
- // revision's candidates and were successful.
- // 3. An array containing the cycle count, current map of candidates
- // for already processed requirements, and a list of remaining
- // requirements whose candidates still need to be calculated.
- // For case 1, rethrow the exception. For case 2, simply return immediately.
- // For case 3, this means we have a cycle so we should continue to populate
- // the candidates where we left off and not record any results globally
- // until we've popped completely out of the cycle.
-
- // Keeps track of the number of times we've reentered this method
- // for the current revision.
- Integer cycleCount = null;
-
- // Keeps track of the candidates we've already calculated for the
- // current revision's requirements.
- Map<BundleRequirement, List<BundleCapability>> localCandidateMap = null;
-
- // Keeps track of the current revision's requirements for which we
- // haven't yet found candidates.
- List<BundleRequirement> remainingReqs = null;
-
- // Get the cache value for the current revision.
- Object cacheValue = m_populateResultCache.get(revision);
-
- // This is case 1.
- if (cacheValue instanceof ResolveException)
- {
- throw (ResolveException) cacheValue;
- }
- // This is case 2.
- else if (cacheValue instanceof Boolean)
- {
- return;
- }
- // This is case 3.
- else if (cacheValue != null)
- {
- // Increment and get the cycle count.
- cycleCount = (Integer)
- (((Object[]) cacheValue)[0]
- = new Integer(((Integer) ((Object[]) cacheValue)[0]).intValue() + 1));
- // Get the already populated candidates.
- localCandidateMap = (Map) ((Object[]) cacheValue)[1];
- // Get the remaining requirements.
- remainingReqs = (List) ((Object[]) cacheValue)[2];
- }
-
- // If there is no cache value for the current revision, then this is
- // the first time we are attempting to populate its candidates, so
- // do some one-time checks and initialization.
- if ((remainingReqs == null) && (localCandidateMap == null))
- {
- // Verify that any native libraries match the current platform.
- ((ResolveContextImpl) rc).checkNativeLibraries(revision);
-
- // Record cycle count.
- cycleCount = new Integer(0);
-
- // Create a local map for populating candidates first, just in case
- // the revision is not resolvable.
- localCandidateMap = new HashMap();
-
- // Create a modifiable list of the revision's requirements.
- remainingReqs = new ArrayList(revision.getDeclaredRequirements(null));
-
- // Add these value to the result cache so we know we are
- // in the middle of populating candidates for the current
- // revision.
- m_populateResultCache.put(revision,
- cacheValue = new Object[] { cycleCount, localCandidateMap, remainingReqs });
- }
-
- // If we have requirements remaining, then find candidates for them.
- while (!remainingReqs.isEmpty())
- {
- BundleRequirement req = remainingReqs.remove(0);
-
- // Ignore non-effective and dynamic requirements.
- String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
- if (!rc.isEffective(req)
- || ((resolution != null)
- && resolution.equals(FelixConstants.RESOLUTION_DYNAMIC)))
- {
- continue;
- }
-
- // Process the candidates, removing any candidates that
- // cannot resolve.
- List<BundleCapability> candidates = rc.findProviders(req, true);
- ResolveException rethrow = processCandidates(rc, revision, candidates);
-
- // First, due to cycles, makes sure we haven't already failed in
- // a deeper recursion.
- Object result = m_populateResultCache.get(revision);
- if (result instanceof ResolveException)
- {
- throw (ResolveException) result;
- }
- // Next, if are no candidates remaining and the requirement is not
- // not optional, then record and throw a resolve exception.
- else if (candidates.isEmpty() && !((BundleRequirementImpl) req).isOptional())
- {
- String msg = "Unable to resolve " + revision
- + ": missing requirement " + req;
- if (rethrow != null)
- {
- msg = msg + " [caused by: " + rethrow.getMessage() + "]";
- }
- rethrow = new ResolveException(msg, revision, req);
- m_populateResultCache.put(revision, rethrow);
- throw rethrow;
- }
- // Otherwise, if we actually have candidates for the requirement, then
- // add them to the local candidate map.
- else if (candidates.size() > 0)
- {
- localCandidateMap.put(req, candidates);
- }
- }
-
- // If we are exiting from a cycle then decrement
- // cycle counter, otherwise record the result.
- if (cycleCount.intValue() > 0)
- {
- ((Object[]) cacheValue)[0] = new Integer(cycleCount.intValue() - 1);
- }
- else if (cycleCount.intValue() == 0)
- {
- // Record that the revision was successfully populated.
- m_populateResultCache.put(revision, Boolean.TRUE);
-
- // Merge local candidate map into global candidate map.
- if (localCandidateMap.size() > 0)
- {
- add(localCandidateMap);
- }
- }
- }
-
- private boolean populateFragmentOndemand(ResolveContext rc, BundleRevision revision)
- throws ResolveException
- {
- // Create a modifiable list of the revision's requirements.
- List<BundleRequirement> remainingReqs =
- new ArrayList(revision.getDeclaredRequirements(null));
- // Find the host requirement.
- BundleRequirement hostReq = null;
- for (Iterator<BundleRequirement> it = remainingReqs.iterator();
- it.hasNext(); )
- {
- BundleRequirement r = it.next();
- if (r.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
- {
- hostReq = r;
- it.remove();
- break;
- }
- }
- // Get candidates hosts and keep any that have been populated.
- List<BundleCapability> hosts = rc.findProviders(hostReq, false);
- for (Iterator<BundleCapability> it = hosts.iterator(); it.hasNext(); )
- {
- BundleCapability host = it.next();
- if (!isPopulated(host.getRevision()))
- {
- it.remove();
- }
- }
- // If there aren't any populated hosts, then we can just
- // return since this fragment isn't needed.
- if (hosts.isEmpty())
- {
- return false;
- }
- // If there are populates host candidates, then finish up
- // some other checks and prepopulate the result cache with
- // the work we've done so far.
- // Verify that any native libraries match the current platform.
- ((ResolveContextImpl) rc).checkNativeLibraries(revision);
- // Record cycle count, but start at -1 since it will
- // be incremented again in populate().
- Integer cycleCount = new Integer(-1);
- // Create a local map for populating candidates first, just in case
- // the revision is not resolvable.
- Map<BundleRequirement, List<BundleCapability>> localCandidateMap =
- new HashMap<BundleRequirement, List<BundleCapability>>();
- // Add the discovered host candidates to the local candidate map.
- localCandidateMap.put(hostReq, hosts);
- // Add these value to the result cache so we know we are
- // in the middle of populating candidates for the current
- // revision.
- m_populateResultCache.put(revision,
- new Object[] { cycleCount, localCandidateMap, remainingReqs });
- return true;
- }
-
- public void populateDynamic(
- ResolveContext rc, BundleRevision revision,
- BundleRequirement req, List<BundleCapability> candidates)
- {
- // Record the revision associated with the dynamic require
- // as a mandatory revision.
- m_mandatoryRevisions.add(revision);
-
- // Add the dynamic imports candidates.
- add(req, candidates);
-
- // Process the candidates, removing any candidates that
- // cannot resolve.
- ResolveException rethrow = processCandidates(rc, revision, candidates);
-
- if (candidates.isEmpty())
- {
- if (rethrow == null)
- {
- rethrow = new ResolveException("Dynamic import failed.", revision, req);
- }
- throw rethrow;
- }
-
- m_populateResultCache.put(revision, Boolean.TRUE);
- }
-
- /**
- * This method performs common processing on the given set of candidates.
- * Specifically, it removes any candidates which cannot resolve and it
- * synthesizes candidates for any candidates coming from any attached
- * fragments, since fragment capabilities only appear once, but technically
- * each host represents a unique capability.
- * @param state the resolver state.
- * @param revision the revision being resolved.
- * @param candidates the candidates to process.
- * @return a resolve exception to be re-thrown, if any, or null.
- */
- private ResolveException processCandidates(
- ResolveContext rc,
- BundleRevision revision,
- List<BundleCapability> candidates)
- {
- // Get satisfying candidates and populate their candidates if necessary.
- ResolveException rethrow = null;
- Set<BundleCapability> fragmentCands = null;
- for (Iterator<BundleCapability> itCandCap = candidates.iterator();
- itCandCap.hasNext(); )
- {
- BundleCapability candCap = itCandCap.next();
-
- boolean isFragment = Util.isFragment(candCap.getRevision());
-
- // If the capability is from a fragment, then record it
- // because we have to insert associated host capabilities
- // if the fragment is already attached to any hosts.
- if (isFragment)
- {
- if (fragmentCands == null)
- {
- fragmentCands = new HashSet<BundleCapability>();
- }
- fragmentCands.add(candCap);
- }
-
- // If the candidate revision is a fragment, then always attempt
- // to populate candidates for its dependency, since it must be
- // attached to a host to be used. Otherwise, if the candidate
- // revision is not already resolved and is not the current version
- // we are trying to populate, then populate the candidates for
- // its dependencies as well.
- // NOTE: Technically, we don't have to check to see if the
- // candidate revision is equal to the current revision, but this
- // saves us from recursing and also simplifies exceptions messages
- // since we effectively chain exception messages for each level
- // of recursion; thus, any avoided recursion results in fewer
- // exceptions to chain when an error does occur.
- if ((isFragment || (candCap.getRevision().getWiring() == null))
- && !candCap.getRevision().equals(revision))
- {
- try
- {
- populateRevision(rc, candCap.getRevision());
- }
- catch (ResolveException ex)
- {
- if (rethrow == null)
- {
- rethrow = ex;
- }
- // Remove the candidate since we weren't able to
- // populate its candidates.
- itCandCap.remove();
- }
- }
- }
-
- // If any of the candidates for the requirement were from a fragment,
- // then also insert synthesized hosted capabilities for any other host
- // to which the fragment is attached since they are all effectively
- // unique capabilities.
- if (fragmentCands != null)
- {
- for (BundleCapability fragCand : fragmentCands)
- {
- // Only necessary for resolved fragments.
- BundleWiring wiring = fragCand.getRevision().getWiring();
- if (wiring != null)
- {
- // Fragments only have host wire, so each wire represents
- // an attached host.
- for (BundleWire wire : wiring.getRequiredWires(null))
- {
- // If the capability is a package, then make sure the
- // host actually provides it in its resolved capabilities,
- // since it may be a substitutable export.
- if (!fragCand.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
- || wire.getProviderWiring().getCapabilities(null).contains(fragCand))
- {
- // Note that we can just add this as a candidate
- // directly, since we know it is already resolved.
- // NOTE: We are synthesizing a hosted capability here,
- // but we are not using a ShadowList like we do when
- // we synthesizing capabilities for unresolved hosts.
- // It is not necessary to use the ShadowList here since
- // the host is resolved, because in that case we can
- // calculate the proper package space by traversing
- // the wiring. In the unresolved case, this isn't possible
- // so we need to use the ShadowList so we can keep
- // a reference to a synthesized resource with attached
- // fragments so we can correctly calculate its package
- // space.
- rc.insertHostedCapability(candidates,
- new WrappedCapability(
- wire.getCapability().getRevision(),
- (BundleCapabilityImpl) fragCand));
- }
- }
- }
- }
- }
-
- return rethrow;
- }
-
- public boolean isPopulated(BundleRevision revision)
- {
- Object value = m_populateResultCache.get(revision);
- return ((value != null) && (value instanceof Boolean));
- }
-
- public ResolveException getResolveException(BundleRevision revision)
- {
- Object value = m_populateResultCache.get(revision);
- return ((value != null) && (value instanceof ResolveException))
- ? (ResolveException) value : null;
- }
-
- /**
- * Adds a requirement and its matching candidates to the internal data
- * structure. This method assumes it owns the data being passed in and
- * does not make a copy. It takes the data and processes, such as calculating
- * which requirements depend on which capabilities and recording any fragments
- * it finds for future merging.
- * @param req the requirement to add.
- * @param candidates the candidates matching the requirement.
- **/
- private void add(BundleRequirement req, List<BundleCapability> candidates)
- {
- if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
- {
- m_fragmentsPresent = true;
- }
-
- // Record the candidates.
- m_candidateMap.put(req, candidates);
- }
-
- /**
- * Adds requirements and candidates in bulk. The outer map is not retained
- * by this method, but the inner data structures are, so they should not
- * be further modified by the caller.
- * @param candidates the bulk requirements and candidates to add.
- **/
- private void add(Map<BundleRequirement, List<BundleCapability>> candidates)
- {
- for (Entry<BundleRequirement, List<BundleCapability>> entry : candidates.entrySet())
- {
- add(entry.getKey(), entry.getValue());
- }
- }
-
- /**
- * Returns the wrapped module associated with the given module. If the module
- * was not wrapped, then the module itself is returned. This is really only
- * needed to determine if the root modules of the resolve have been wrapped.
- * @param m the module whose wrapper is desired.
- * @return the wrapper module or the module itself if it was not wrapped.
- **/
- public BundleRevision getWrappedHost(BundleRevision m)
- {
- BundleRevision wrapped = m_allWrappedHosts.get(m);
- return (wrapped == null) ? m : wrapped;
- }
-
- /**
- * Gets the candidates associated with a given requirement.
- * @param req the requirement whose candidates are desired.
- * @return the matching candidates or null.
- **/
- public List<BundleCapability> getCandidates(BundleRequirement req)
- {
- return m_candidateMap.get(req);
- }
-
- /**
- * Merges fragments into their hosts. It does this by wrapping all host
- * modules and attaching their selected fragments, removing all unselected
- * fragment modules, and replacing all occurrences of the original fragments
- * in the internal data structures with the wrapped host modules instead.
- * Thus, fragment capabilities and requirements are merged into the appropriate
- * host and the candidates for the fragment now become candidates for the host.
- * Likewise, any module depending on a fragment now depend on the host. Note
- * that this process is sort of like multiplication, since one fragment that
- * can attach to two hosts effectively gets multiplied across the two hosts.
- * So, any modules being satisfied by the fragment will end up having the
- * two hosts as potential candidates, rather than the single fragment.
- * @param existingSingletons existing resolved singletons.
- * @throws ResolveException if the removal of any unselected fragments result
- * in the root module being unable to resolve.
- **/
- public void prepare(ResolveContext rc)
- {
- // Maps a host capability to a map containing its potential fragments;
- // the fragment map maps a fragment symbolic name to a map that maps
- // a version to a list of fragments requirements matching that symbolic
- // name and version.
- Map<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
- hostFragments = Collections.EMPTY_MAP;
- if (m_fragmentsPresent)
- {
- hostFragments = populateDependents();
- }
-
- // This method performs the following steps:
- // 1. Select the fragments to attach to a given host.
- // 2. Wrap hosts and attach fragments.
- // 3. Remove any unselected fragments. This is necessary because
- // other revisions may depend on the capabilities of unselected
- // fragments, so we need to remove the unselected fragments and
- // any revisions that depends on them, which could ultimately cause
- // the entire resolve to fail.
- // 4. Replace all fragments with any host it was merged into
- // (effectively multiplying it).
- // * This includes setting candidates for attached fragment
- // requirements as well as replacing fragment capabilities
- // with host's attached fragment capabilities.
-
- // Steps 1 and 2
- List<WrappedRevision> hostRevisions = new ArrayList<WrappedRevision>();
- List<BundleRevision> unselectedFragments = new ArrayList<BundleRevision>();
- for (Entry<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
- hostEntry : hostFragments.entrySet())
- {
- // Step 1
- BundleCapability hostCap = hostEntry.getKey();
- Map<String, Map<Version, List<BundleRequirement>>> fragments
- = hostEntry.getValue();
- List<BundleRevision> selectedFragments = new ArrayList<BundleRevision>();
- for (Entry<String, Map<Version, List<BundleRequirement>>> fragEntry
- : fragments.entrySet())
- {
- boolean isFirst = true;
- for (Entry<Version, List<BundleRequirement>> versionEntry
- : fragEntry.getValue().entrySet())
- {
- for (BundleRequirement hostReq : versionEntry.getValue())
- {
- // Selecting the first fragment in each entry, which
- // is equivalent to selecting the highest version of
- // each fragment with a given symbolic name.
- if (isFirst)
- {
- selectedFragments.add(hostReq.getRevision());
- isFirst = false;
- }
- // For any fragment that wasn't selected, remove the
- // current host as a potential host for it and remove it
- // as a dependent on the host. If there are no more
- // potential hosts for the fragment, then mark it as
- // unselected for later removal.
- else
- {
- m_dependentMap.get(hostCap).remove(hostReq);
- List<BundleCapability> hosts = m_candidateMap.get(hostReq);
- hosts.remove(hostCap);
- if (hosts.isEmpty())
- {
- unselectedFragments.add(hostReq.getRevision());
- }
- }
- }
- }
- }
-
- // Step 2
- WrappedRevision wrappedHost =
- new WrappedRevision(hostCap.getRevision(), selectedFragments);
- hostRevisions.add(wrappedHost);
- m_allWrappedHosts.put(hostCap.getRevision(), wrappedHost);
- }
-
- // Step 3
- for (BundleRevision br : unselectedFragments)
- {
- removeRevision(br,
- new ResolveException(
- "Fragment was not selected for attachment.", br, null));
- }
-
- // Step 4
- for (WrappedRevision hostRevision : hostRevisions)
- {
- // Replaces capabilities from fragments with the capabilities
- // from the merged host.
- for (BundleCapability c : hostRevision.getDeclaredCapabilities(null))
- {
- // Don't replace the host capability, since the fragment will
- // really be attached to the original host, not the wrapper.
- if (!c.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
- {
- BundleCapability origCap = ((HostedCapability) c).getDeclaredCapability();
- // Note that you might think we could remove the original cap
- // from the dependent map, but you can't since it may come from
- // a fragment that is attached to multiple hosts, so each host
- // will need to make their own copy.
- Set<BundleRequirement> dependents = m_dependentMap.get(origCap);
- if (dependents != null)
- {
- dependents = new HashSet<BundleRequirement>(dependents);
- m_dependentMap.put(c, dependents);
- for (BundleRequirement r : dependents)
- {
- // We have synthesized hosted capabilities for all
- // fragments that have been attached to hosts by
- // wrapping the host bundle and their attached
- // fragments. We need to use the ResolveContext to
- // determine the proper priority order for hosted
- // capabilities since the order may depend on the
- // declaring host/fragment combination. However,
- // internally we completely wrap the host revision
- // and make all capabilities/requirements point back
- // to the wrapped host not the declaring host. The
- // ResolveContext expects HostedCapabilities to point
- // to the declaring revision, so we need two separate
- // candidate lists: one for the ResolveContext with
- // HostedCapabilities pointing back to the declaring
- // host and one for the resolver with HostedCapabilities
- // pointing back to the wrapped host. We ask the
- // ResolveContext to insert its appropriate HostedCapability
- // into its list, then we mirror the insert into a
- // shadow list with the resolver's HostedCapability.
- // We only need to ask the ResolveContext to find
- // the insert position for fragment caps since these
- // were synthesized and we don't know their priority.
- // However, in the resolver's candidate list we need
- // to replace all caps with the wrapped caps, no
- // matter if they come from the host or fragment,
- // since we are completing replacing the declaring
- // host and fragments with the wrapped host.
- List<BundleCapability> cands = m_candidateMap.get(r);
- if (!(cands instanceof ShadowList))
- {
- ShadowList<BundleCapability> shadow =
- new ShadowList<BundleCapability>(cands);
- m_candidateMap.put(r, shadow);
- cands = shadow;
- }
-
- // If the original capability is from a fragment, then
- // ask the ResolveContext to insert it and update the
- // shadow copy of the list accordingly.
- if (!origCap.getRevision().equals(hostRevision.getHost()))
- {
- List<BundleCapability> original = ((ShadowList) cands).getOriginal();
- int removeIdx = original.indexOf(origCap);
- original.remove(removeIdx);
- int insertIdx = rc.insertHostedCapability(
- original,
- new SimpleHostedCapability(hostRevision.getHost(), origCap));
- cands.remove(removeIdx);
- cands.add(insertIdx, c);
- }
- // If the original capability is from the host, then
- // we just need to replace it in the shadow list.
- else
- {
- int idx = cands.indexOf(origCap);
- cands.set(idx, c);
- }
- }
- }
- }
- }
-
- // Copy candidates for fragment requirements to the host.
- for (BundleRequirement r : hostRevision.getDeclaredRequirements(null))
- {
- BundleRequirement origReq =
- ((WrappedRequirement) r).getOriginalRequirement();
- List<BundleCapability> cands = m_candidateMap.get(origReq);
- if (cands != null)
- {
- m_candidateMap.put(r, new ArrayList<BundleCapability>(cands));
- for (BundleCapability cand : cands)
- {
- Set<BundleRequirement> dependents = m_dependentMap.get(cand);
- dependents.remove(origReq);
- dependents.add(r);
- }
- }
- }
- }
-
- // Lastly, verify that all mandatory revisions are still
- // populated, since some might have become unresolved after
- // selecting fragments/singletons.
- for (BundleRevision br : m_mandatoryRevisions)
- {
- if (!isPopulated(br))
- {
- throw getResolveException(br);
- }
- }
- }
-
- // Maps a host capability to a map containing its potential fragments;
- // the fragment map maps a fragment symbolic name to a map that maps
- // a version to a list of fragments requirements matching that symbolic
- // name and version.
- private Map<BundleCapability,
- Map<String, Map<Version, List<BundleRequirement>>>> populateDependents()
- {
- Map<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
- hostFragments = new HashMap<BundleCapability,
- Map<String, Map<Version, List<BundleRequirement>>>>();
- for (Entry<BundleRequirement, List<BundleCapability>> entry : m_candidateMap.entrySet())
- {
- BundleRequirement req = entry.getKey();
- List<BundleCapability> caps = entry.getValue();
- for (BundleCapability cap : caps)
- {
- // Record the requirement as dependent on the capability.
- Set<BundleRequirement> dependents = m_dependentMap.get(cap);
- if (dependents == null)
- {
- dependents = new HashSet<BundleRequirement>();
- m_dependentMap.put(cap, dependents);
- }
- dependents.add(req);
-
- // Keep track of hosts and associated fragments.
- if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
- {
- Map<String, Map<Version, List<BundleRequirement>>>
- fragments = hostFragments.get(cap);
- if (fragments == null)
- {
- fragments = new HashMap<String, Map<Version, List<BundleRequirement>>>();
- hostFragments.put(cap, fragments);
- }
- Map<Version, List<BundleRequirement>> fragmentVersions =
- fragments.get(req.getRevision().getSymbolicName());
- if (fragmentVersions == null)
- {
- fragmentVersions =
- new TreeMap<Version, List<BundleRequirement>>(Collections.reverseOrder());
- fragments.put(req.getRevision().getSymbolicName(), fragmentVersions);
- }
- List<BundleRequirement> actual = fragmentVersions.get(req.getRevision().getVersion());
- if (actual == null)
- {
- actual = new ArrayList<BundleRequirement>();
- fragmentVersions.put(req.getRevision().getVersion(), actual);
- }
- actual.add(req);
- }
- }
- }
-
- return hostFragments;
- }
-
- /**
- * Removes a module from the internal data structures if it wasn't selected
- * as a fragment or a singleton. This process may cause other modules to
- * become unresolved if they depended on the module's capabilities and there
- * is no other candidate.
- * @param revision the module to remove.
- * @throws ResolveException if removing the module caused the resolve to fail.
- **/
- private void removeRevision(BundleRevision revision, ResolveException ex)
- {
- // Add removal reason to result cache.
- m_populateResultCache.put(revision, ex);
- // Remove from dependents.
- Set<BundleRevision> unresolvedRevisions = new HashSet<BundleRevision>();
- remove(revision, unresolvedRevisions);
- // Remove dependents that failed as a result of removing revision.
- while (!unresolvedRevisions.isEmpty())
- {
- Iterator<BundleRevision> it = unresolvedRevisions.iterator();
- revision = it.next();
- it.remove();
- remove(revision, unresolvedRevisions);
- }
- }
-
- /**
- * Removes the specified module from the internal data structures, which
- * involves removing its requirements and its capabilities. This may cause
- * other modules to become unresolved as a result.
- * @param br the module to remove.
- * @param unresolvedRevisions a list to containing any additional modules that
- * that became unresolved as a result of removing this module and will
- * also need to be removed.
- * @throws ResolveException if removing the module caused the resolve to fail.
- **/
- private void remove(BundleRevision br, Set<BundleRevision> unresolvedRevisions)
- throws ResolveException
- {
- for (BundleRequirement r : br.getDeclaredRequirements(null))
- {
- remove(r);
- }
-
- for (BundleCapability c : br.getDeclaredCapabilities(null))
- {
- remove(c, unresolvedRevisions);
- }
- }
-
- /**
- * Removes a requirement from the internal data structures.
- * @param req the requirement to remove.
- **/
- private void remove(BundleRequirement req)
- {
- boolean isFragment = req.getNamespace().equals(BundleRevision.HOST_NAMESPACE);
-
- List<BundleCapability> candidates = m_candidateMap.remove(req);
- if (candidates != null)
- {
- for (BundleCapability cap : candidates)
- {
- Set<BundleRequirement> dependents = m_dependentMap.get(cap);
- if (dependents != null)
- {
- dependents.remove(req);
- }
- }
- }
- }
-
- /**
- * Removes a capability from the internal data structures. This may cause
- * other modules to become unresolved as a result.
- * @param c the capability to remove.
- * @param unresolvedRevisions a list to containing any additional modules that
- * that became unresolved as a result of removing this module and will
- * also need to be removed.
- * @throws ResolveException if removing the module caused the resolve to fail.
- **/
- private void remove(BundleCapability c, Set<BundleRevision> unresolvedRevisions)
- throws ResolveException
- {
- Set<BundleRequirement> dependents = m_dependentMap.remove(c);
- if (dependents != null)
- {
- for (BundleRequirement r : dependents)
- {
- List<BundleCapability> candidates = m_candidateMap.get(r);
- candidates.remove(c);
- if (candidates.isEmpty())
- {
- m_candidateMap.remove(r);
- if (!((BundleRequirementImpl) r).isOptional())
- {
- String msg = "Unable to resolve " + r.getRevision()
- + ": missing requirement " + r;
- m_populateResultCache.put(
- r.getRevision(), new ResolveException(msg, r.getRevision(), r));
- unresolvedRevisions.add(r.getRevision());
- }
- }
- }
- }
- }
-
- /**
- * Creates a copy of the Candidates object. This is used for creating
- * permutations when package space conflicts are discovered.
- * @return copy of this Candidates object.
- **/
- public Candidates copy()
- {
- Map<BundleCapability, Set<BundleRequirement>> dependentMap =
- new HashMap<BundleCapability, Set<BundleRequirement>>();
- for (Entry<BundleCapability, Set<BundleRequirement>> entry : m_dependentMap.entrySet())
- {
- Set<BundleRequirement> dependents = new HashSet<BundleRequirement>(entry.getValue());
- dependentMap.put(entry.getKey(), dependents);
- }
-
- Map<BundleRequirement, List<BundleCapability>> candidateMap =
- new HashMap<BundleRequirement, List<BundleCapability>>();
- for (Entry<BundleRequirement, List<BundleCapability>> entry
- : m_candidateMap.entrySet())
- {
- List<BundleCapability> candidates =
- new ArrayList<BundleCapability>(entry.getValue());
- candidateMap.put(entry.getKey(), candidates);
- }
-
- return new Candidates(
- m_mandatoryRevisions, dependentMap, candidateMap,
- m_allWrappedHosts, m_populateResultCache, m_fragmentsPresent);
- }
-
- public void dump()
- {
- // Create set of all revisions from requirements.
- Set<BundleRevision> revisions = new HashSet<BundleRevision>();
- for (Entry<BundleRequirement, List<BundleCapability>> entry
- : m_candidateMap.entrySet())
- {
- revisions.add(entry.getKey().getRevision());
- }
- // Now dump the revisions.
- System.out.println("=== BEGIN CANDIDATE MAP ===");
- for (BundleRevision br : revisions)
- {
- System.out.println(" " + br
- + " (" + ((br.getWiring() != null) ? "RESOLVED)" : "UNRESOLVED)"));
- List<BundleRequirement> reqs = (br.getWiring() != null)
- ? br.getWiring().getRequirements(null)
- : br.getDeclaredRequirements(null);
- for (BundleRequirement req : reqs)
- {
- List<BundleCapability> candidates = m_candidateMap.get(req);
- if ((candidates != null) && (candidates.size() > 0))
- {
- System.out.println(" " + req + ": " + candidates);
- }
- }
- reqs = (br.getWiring() != null)
- ? Util.getDynamicRequirements(br.getWiring().getRequirements(null))
- : Util.getDynamicRequirements(br.getDeclaredRequirements(null));
- for (BundleRequirement req : reqs)
- {
- List<BundleCapability> candidates = m_candidateMap.get(req);
- if ((candidates != null) && (candidates.size() > 0))
- {
- System.out.println(" " + req + ": " + candidates);
- }
- }
- }
- System.out.println("=== END CANDIDATE MAP ===");
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java b/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
deleted file mode 100644
index fc45301..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2012). All Rights Reserved.
- *
- * 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.resolver;
-
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRevision;
-
-public interface HostedCapability extends BundleCapability {
-
- BundleRevision getRevision();
-
- BundleCapability getDeclaredCapability();
-}
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java
deleted file mode 100644
index 2af0696..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2011, 2012). All Rights Reserved.
- *
- * 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.resolver;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWiring;
-
-public abstract class ResolveContext
-{
- public Collection<BundleRevision> getMandatoryRevisions()
- {
- return emptyCollection();
- }
-
- public Collection<BundleRevision> getOptionalRevisions()
- {
- return emptyCollection();
- }
-
- private static <T> Collection<T> emptyCollection()
- {
- return Collections.EMPTY_LIST;
- }
-
- public abstract List<BundleCapability> findProviders(BundleRequirement br, boolean obeyMandatory);
-
- public abstract int insertHostedCapability(List<BundleCapability> caps, HostedCapability hc);
-
- public abstract boolean isEffective(BundleRequirement br);
-
- public abstract Map<BundleRevision, BundleWiring> getWirings();
-}
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java
index 360ef3d..9d9a232 100755
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveException.java
@@ -20,8 +20,9 @@
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.service.resolver.ResolutionException;
-public class ResolveException extends RuntimeException
+public class ResolveException extends ResolutionException
{
private final BundleRevision m_revision;
private final BundleRequirement m_req;
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
deleted file mode 100644
index 107e4a7..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-
-public interface Resolver
-{
- Map<BundleRevision, List<ResolverWire>> resolve(ResolveContext rc);
- Map<BundleRevision, List<ResolverWire>> resolve(
- ResolveContext rc, BundleRevision revision, String pkgName);
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
deleted file mode 100644
index 2512144..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
+++ /dev/null
@@ -1,1811 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.SortedSet;
-import org.apache.felix.framework.BundleWiringImpl;
-import org.apache.felix.framework.Logger;
-import org.apache.felix.framework.ResolveContextImpl;
-import org.apache.felix.framework.capabilityset.CapabilitySet;
-import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-import org.apache.felix.framework.wiring.BundleRequirementImpl;
-import org.osgi.framework.Constants;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWire;
-
-public class ResolverImpl implements Resolver
-{
- private final Logger m_logger;
-
- // Holds candidate permutations based on permutating "uses" chains.
- // These permutations are given higher priority.
- private final List<Candidates> m_usesPermutations = new ArrayList<Candidates>();
- // Holds candidate permutations based on permutating requirement candidates.
- // These permutations represent backtracking on previous decisions.
- private final List<Candidates> m_importPermutations = new ArrayList<Candidates>();
-
- public ResolverImpl(Logger logger)
- {
- m_logger = logger;
- }
-
- public Map<BundleRevision, List<ResolverWire>> resolve(ResolveContext rc)
- {
- Map<BundleRevision, List<ResolverWire>> wireMap =
- new HashMap<BundleRevision, List<ResolverWire>>();
- Map<BundleRevision, Packages> revisionPkgMap =
- new HashMap<BundleRevision, Packages>();
-
- Collection<BundleRevision> mandatoryRevisions = rc.getMandatoryRevisions();
- Collection<BundleRevision> optionalRevisions = rc.getOptionalRevisions();
- Collection<BundleRevision> ondemandFragments = (rc instanceof ResolveContextImpl)
- ? ((ResolveContextImpl) rc).getOndemandRevisions() : Collections.EMPTY_LIST;
- boolean retry;
- do
- {
- retry = false;
-
- try
- {
- // Create object to hold all candidates.
- Candidates allCandidates = new Candidates();
-
- // Populate mandatory revisions; since these are mandatory
- // revisions, failure throws a resolve exception.
- for (Iterator<BundleRevision> it = mandatoryRevisions.iterator();
- it.hasNext(); )
- {
- BundleRevision br = it.next();
- if (Util.isFragment(br) || (br.getWiring() == null))
- {
- allCandidates.populate(rc, br, Candidates.MANDATORY);
- }
- else
- {
- it.remove();
- }
- }
-
- // Populate optional revisions; since these are optional
- // revisions, failure does not throw a resolve exception.
- for (BundleRevision br : optionalRevisions)
- {
- boolean isFragment = Util.isFragment(br);
- if (isFragment || (br.getWiring() == null))
- {
- allCandidates.populate(rc, br, Candidates.OPTIONAL);
- }
- }
-
- // Populate ondemand fragments; since these are optional
- // revisions, failure does not throw a resolve exception.
- for (BundleRevision br : ondemandFragments)
- {
- boolean isFragment = Util.isFragment(br);
- if (isFragment)
- {
- allCandidates.populate(rc, br, Candidates.ON_DEMAND);
- }
- }
-
- // Merge any fragments into hosts.
- allCandidates.prepare(rc);
-
- // Create a combined list of populated revisions; for
- // optional revisions. We do not need to consider ondemand
- // fragments, since they will only be pulled in if their
- // host is already present.
- Set<BundleRevision> allRevisions =
- new HashSet<BundleRevision>(mandatoryRevisions);
- for (BundleRevision br : optionalRevisions)
- {
- if (allCandidates.isPopulated(br))
- {
- allRevisions.add(br);
- }
- }
-
- // Record the initial candidate permutation.
- m_usesPermutations.add(allCandidates);
-
- ResolveException rethrow = null;
-
- // If a populated revision is a fragment, then its host
- // must ultimately be verified, so store its host requirement
- // to use for package space calculation.
- Map<BundleRevision, List<BundleRequirement>> hostReqs =
- new HashMap<BundleRevision, List<BundleRequirement>>();
- for (BundleRevision br : allRevisions)
- {
- if (Util.isFragment(br))
- {
- hostReqs.put(
- br,
- br.getDeclaredRequirements(BundleRevision.HOST_NAMESPACE));
- }
- }
-
- do
- {
- rethrow = null;
-
- revisionPkgMap.clear();
- m_packageSourcesCache.clear();
-
- allCandidates = (m_usesPermutations.size() > 0)
- ? m_usesPermutations.remove(0)
- : m_importPermutations.remove(0);
-//allCandidates.dump();
-
- for (BundleRevision br : allRevisions)
- {
- BundleRevision target = br;
-
- // If we are resolving a fragment, then get its
- // host candidate and verify it instead.
- List<BundleRequirement> hostReq = hostReqs.get(br);
- if (hostReq != null)
- {
- target = allCandidates.getCandidates(hostReq.get(0))
- .iterator().next().getRevision();
- }
-
- calculatePackageSpaces(
- allCandidates.getWrappedHost(target), allCandidates, revisionPkgMap,
- new HashMap(), new HashSet());
-//System.out.println("+++ PACKAGE SPACES START +++");
-//dumpRevisionPkgMap(revisionPkgMap);
-//System.out.println("+++ PACKAGE SPACES END +++");
-
- try
- {
- checkPackageSpaceConsistency(
- rc, false, allCandidates.getWrappedHost(target),
- allCandidates, revisionPkgMap, new HashMap());
- }
- catch (ResolveException ex)
- {
- rethrow = ex;
- }
- }
- }
- while ((rethrow != null)
- && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0)));
-
- // If there is a resolve exception, then determine if an
- // optionally resolved revision is to blame (typically a fragment).
- // If so, then remove the optionally resolved resolved and try
- // again; otherwise, rethrow the resolve exception.
- if (rethrow != null)
- {
- BundleRevision faultyRevision =
- getDeclaringBundleRevision(rethrow.getRevision());
- if (rethrow.getRequirement() instanceof WrappedRequirement)
- {
- faultyRevision =
- ((WrappedRequirement) rethrow.getRequirement())
- .getOriginalRequirement().getRevision();
- }
- if (optionalRevisions.remove(faultyRevision))
- {
- retry = true;
- }
- else if (ondemandFragments.remove(faultyRevision))
- {
- retry = true;
- }
- else
- {
- throw rethrow;
- }
- }
- // If there is no exception to rethrow, then this was a clean
- // resolve, so populate the wire map.
- else
- {
- for (BundleRevision br : allRevisions)
- {
- BundleRevision target = br;
-
- // If we are resolving a fragment, then we
- // actually want to populate its host's wires.
- List<BundleRequirement> hostReq = hostReqs.get(br);
- if (hostReq != null)
- {
- target = allCandidates.getCandidates(hostReq.get(0))
- .iterator().next().getRevision();
- }
-
- if (allCandidates.isPopulated(target))
- {
- wireMap =
- populateWireMap(
- allCandidates.getWrappedHost(target),
- revisionPkgMap, wireMap, allCandidates);
- }
- }
- }
- }
- finally
- {
- // Always clear the state.
- m_usesPermutations.clear();
- m_importPermutations.clear();
- }
- }
- while (retry);
-
- return wireMap;
- }
-
- public Map<BundleRevision, List<ResolverWire>> resolve(
- ResolveContext rc, BundleRevision revision, String pkgName)
- {
- // We can only create a dynamic import if the following
- // conditions are met:
- // 1. The specified revision is resolved.
- // 2. The package in question is not already imported.
- // 3. The package in question is not accessible via require-bundle.
- // 4. The package in question is not exported by the revision.
- // 5. The package in question matches a dynamic import of the revision.
- // The following call checks all of these conditions and returns
- // the associated dynamic import and matching capabilities.
- Candidates allCandidates =
- getDynamicImportCandidates(rc, revision, pkgName);
- if (allCandidates != null)
- {
- Collection<BundleRevision> ondemandFragments = (rc instanceof ResolveContextImpl)
- ? ((ResolveContextImpl) rc).getOndemandRevisions() : Collections.EMPTY_LIST;
-
- Map<BundleRevision, List<ResolverWire>> wireMap =
- new HashMap<BundleRevision, List<ResolverWire>>();
- Map<BundleRevision, Packages> revisionPkgMap =
- new HashMap<BundleRevision, Packages>();
-
- boolean retry;
- do
- {
- retry = false;
-
- try
- {
- // Try to populate optional fragments.
- for (BundleRevision br : ondemandFragments)
- {
- if (Util.isFragment(br))
- {
- allCandidates.populate(rc, br, Candidates.ON_DEMAND);
- }
- }
-
- // Merge any fragments into hosts.
- allCandidates.prepare(rc);
-
- // Record the initial candidate permutation.
- m_usesPermutations.add(allCandidates);
-
- ResolveException rethrow = null;
-
- do
- {
- rethrow = null;
-
- revisionPkgMap.clear();
- m_packageSourcesCache.clear();
-
- allCandidates = (m_usesPermutations.size() > 0)
- ? m_usesPermutations.remove(0)
- : m_importPermutations.remove(0);
-//allCandidates.dump();
-
- // For a dynamic import, the instigating revision
- // will never be a fragment since fragments never
- // execute code, so we don't need to check for
- // this case like we do for a normal resolve.
-
- calculatePackageSpaces(
- allCandidates.getWrappedHost(revision), allCandidates, revisionPkgMap,
- new HashMap(), new HashSet());
-//System.out.println("+++ PACKAGE SPACES START +++");
-//dumpRevisionPkgMap(revisionPkgMap);
-//System.out.println("+++ PACKAGE SPACES END +++");
-
- try
- {
- checkPackageSpaceConsistency(
- rc, false, allCandidates.getWrappedHost(revision),
- allCandidates, revisionPkgMap, new HashMap());
- }
- catch (ResolveException ex)
- {
- rethrow = ex;
- }
- }
- while ((rethrow != null)
- && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0)));
-
- // If there is a resolve exception, then determine if an
- // optionally resolved revision is to blame (typically a fragment).
- // If so, then remove the optionally resolved revision and try
- // again; otherwise, rethrow the resolve exception.
- if (rethrow != null)
- {
- BundleRevision faultyRevision =
- getDeclaringBundleRevision(rethrow.getRevision());
- if (rethrow.getRequirement() instanceof WrappedRequirement)
- {
- faultyRevision =
- ((WrappedRequirement) rethrow.getRequirement())
- .getOriginalRequirement().getRevision();
- }
- if (ondemandFragments.remove(faultyRevision))
- {
- retry = true;
- }
- else
- {
- throw rethrow;
- }
- }
- // If there is no exception to rethrow, then this was a clean
- // resolve, so populate the wire map.
- else
- {
- wireMap = populateDynamicWireMap(
- revision, pkgName, revisionPkgMap, wireMap, allCandidates);
- return wireMap;
- }
- }
- finally
- {
- // Always clear the state.
- m_usesPermutations.clear();
- m_importPermutations.clear();
- }
- }
- while (retry);
- }
-
- return null;
- }
-
- private static Candidates getDynamicImportCandidates(
- ResolveContext rc, BundleRevision revision, String pkgName)
- {
- // Unresolved revisions cannot dynamically import, nor can the default
- // package be dynamically imported.
- if ((revision.getWiring() == null) || pkgName.length() == 0)
- {
- return null;
- }
-
- // If the revision doesn't have dynamic imports, then just return
- // immediately.
- List<BundleRequirement> dynamics =
- Util.getDynamicRequirements(revision.getWiring().getRequirements(null));
- if ((dynamics == null) || dynamics.isEmpty())
- {
- return null;
- }
-
- // If the revision exports this package, then we cannot
- // attempt to dynamically import it.
- for (BundleCapability cap : revision.getWiring().getCapabilities(null))
- {
- if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
- && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
- {
- return null;
- }
- }
-
- // If this revision already imports or requires this package, then
- // we cannot dynamically import it.
- if (((BundleWiringImpl) revision.getWiring()).hasPackageSource(pkgName))
- {
- return null;
- }
-
- // Determine if any providers of the package exist.
- Map<String, Object> attrs = Collections.singletonMap(
- BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
- BundleRequirementImpl req = new BundleRequirementImpl(
- revision,
- BundleRevision.PACKAGE_NAMESPACE,
- Collections.EMPTY_MAP,
- attrs);
- List<BundleCapability> candidates = rc.findProviders(req, false);
-
- // Try to find a dynamic requirement that matches the capabilities.
- BundleRequirementImpl dynReq = null;
- for (int dynIdx = 0;
- (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size());
- dynIdx++)
- {
- for (Iterator<BundleCapability> itCand = candidates.iterator();
- (dynReq == null) && itCand.hasNext(); )
- {
- BundleCapability cap = itCand.next();
- if (CapabilitySet.matches(
- (BundleCapabilityImpl) cap,
- ((BundleRequirementImpl) dynamics.get(dynIdx)).getFilter()))
- {
- dynReq = (BundleRequirementImpl) dynamics.get(dynIdx);
- }
- }
- }
-
- // If we found a matching dynamic requirement, then filter out
- // any candidates that do not match it.
- if (dynReq != null)
- {
- for (Iterator<BundleCapability> itCand = candidates.iterator();
- itCand.hasNext(); )
- {
- BundleCapability cap = itCand.next();
- if (!CapabilitySet.matches(
- (BundleCapabilityImpl) cap, dynReq.getFilter()))
- {
- itCand.remove();
- }
- }
- }
- else
- {
- candidates.clear();
- }
-
- Candidates allCandidates = null;
-
- if (candidates.size() > 0)
- {
- allCandidates = new Candidates();
- allCandidates.populateDynamic(rc, revision, dynReq, candidates);
- }
-
- return allCandidates;
- }
-
- private void calculatePackageSpaces(
- BundleRevision revision,
- Candidates allCandidates,
- Map<BundleRevision, Packages> revisionPkgMap,
- Map<BundleCapability, List<BundleRevision>> usesCycleMap,
- Set<BundleRevision> cycle)
- {
- if (cycle.contains(revision))
- {
- return;
- }
- cycle.add(revision);
-
- // Make sure package space hasn't already been calculated.
- Packages revisionPkgs = revisionPkgMap.get(revision);
- if (revisionPkgs != null)
- {
- if (revisionPkgs.m_isCalculated)
- {
- return;
- }
- else
- {
- revisionPkgs.m_isCalculated = true;
- }
- }
-
- // Create parallel arrays for requirement and proposed candidate
- // capability or actual capability if revision is resolved or not.
- List<BundleRequirement> reqs = new ArrayList();
- List<BundleCapability> caps = new ArrayList();
- boolean isDynamicImporting = false;
- if (revision.getWiring() != null)
- {
- // Use wires to get actual requirements and satisfying capabilities.
- for (BundleWire wire : revision.getWiring().getRequiredWires(null))
- {
- // Wrap the requirement as a hosted requirement if it comes
- // from a fragment, since we will need to know the host. We
- // also need to wrap if the requirement is a dynamic import,
- // since that requirement will be shared with any other
- // matching dynamic imports.
- BundleRequirement r = wire.getRequirement();
- if (!r.getRevision().equals(wire.getRequirerWiring().getRevision())
- || ((r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE) != null)
- && r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE).equals("dynamic")))
- {
- r = new WrappedRequirement(
- wire.getRequirerWiring().getRevision(),
- (BundleRequirementImpl) r);
- }
- // Wrap the capability as a hosted capability if it comes
- // from a fragment, since we will need to know the host.
- BundleCapability c = wire.getCapability();
- if (!c.getRevision().equals(wire.getProviderWiring().getRevision()))
- {
- c = new WrappedCapability(
- wire.getProviderWiring().getRevision(),
- (BundleCapabilityImpl) c);
- }
- reqs.add(r);
- caps.add(c);
- }
-
- // Since the revision is resolved, it could be dynamically importing,
- // so check to see if there are candidates for any of its dynamic
- // imports.
- for (BundleRequirement req
- : Util.getDynamicRequirements(revision.getWiring().getRequirements(null)))
- {
- // Get the candidates for the current requirement.
- List<BundleCapability> candCaps = allCandidates.getCandidates(req);
- // Optional requirements may not have any candidates.
- if (candCaps == null)
- {
- continue;
- }
-
- // Grab first (i.e., highest priority) candidate.
- BundleCapability cap = candCaps.get(0);
- reqs.add(req);
- caps.add(cap);
- isDynamicImporting = true;
- // Can only dynamically import one at a time, so break
- // out of the loop after the first.
- break;
- }
- }
- else
- {
- for (BundleRequirement req : revision.getDeclaredRequirements(null))
- {
- String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
- if ((resolution == null)
- || !resolution.equals(FelixConstants.RESOLUTION_DYNAMIC))
- {
- // Get the candidates for the current requirement.
- List<BundleCapability> candCaps = allCandidates.getCandidates(req);
- // Optional requirements may not have any candidates.
- if (candCaps == null)
- {
- continue;
- }
-
- // Grab first (i.e., highest priority) candidate.
- BundleCapability cap = candCaps.get(0);
- reqs.add(req);
- caps.add(cap);
- }
- }
- }
-
- // First, add all exported packages to the target revision's package space.
- calculateExportedPackages(revision, allCandidates, revisionPkgMap);
- revisionPkgs = revisionPkgMap.get(revision);
-
- // Second, add all imported packages to the target revision's package space.
- for (int i = 0; i < reqs.size(); i++)
- {
- BundleRequirement req = reqs.get(i);
- BundleCapability cap = caps.get(i);
- calculateExportedPackages(cap.getRevision(), allCandidates, revisionPkgMap);
- mergeCandidatePackages(
- revision, req, cap, revisionPkgMap, allCandidates,
- new HashMap<BundleRevision, List<BundleCapability>>());
- }
-
- // Third, have all candidates to calculate their package spaces.
- for (int i = 0; i < caps.size(); i++)
- {
- calculatePackageSpaces(
- caps.get(i).getRevision(), allCandidates, revisionPkgMap,
- usesCycleMap, cycle);
- }
-
- // Fourth, if the target revision is unresolved or is dynamically importing,
- // then add all the uses constraints implied by its imported and required
- // packages to its package space.
- // NOTE: We do not need to do this for resolved revisions because their
- // package space is consistent by definition and these uses constraints
- // are only needed to verify the consistency of a resolving revision. The
- // only exception is if a resolved revision is dynamically importing, then
- // we need to calculate its uses constraints again to make sure the new
- // import is consistent with the existing package space.
- if ((revision.getWiring() == null) || isDynamicImporting)
- {
- // Merge uses constraints from required capabilities.
- for (int i = 0; i < reqs.size(); i++)
- {
- BundleRequirement req = reqs.get(i);
- BundleCapability cap = caps.get(i);
- // Ignore bundle/package requirements, since they are
- // considered below.
- if (!req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE)
- && !req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- List<BundleRequirement> blameReqs = new ArrayList();
- blameReqs.add(req);
-
- mergeUses(
- revision,
- revisionPkgs,
- cap,
- blameReqs,
- revisionPkgMap,
- allCandidates,
- usesCycleMap);
- }
- }
- // Merge uses constraints from imported packages.
- for (Entry<String, List<Blame>> entry : revisionPkgs.m_importedPkgs.entrySet())
- {
- for (Blame blame : entry.getValue())
- {
- // Ignore revisions that import from themselves.
- if (!blame.m_cap.getRevision().equals(revision))
- {
- List<BundleRequirement> blameReqs = new ArrayList();
- blameReqs.add(blame.m_reqs.get(0));
-
- mergeUses(
- revision,
- revisionPkgs,
- blame.m_cap,
- blameReqs,
- revisionPkgMap,
- allCandidates,
- usesCycleMap);
- }
- }
- }
- // Merge uses constraints from required bundles.
- for (Entry<String, List<Blame>> entry : revisionPkgs.m_requiredPkgs.entrySet())
- {
- for (Blame blame : entry.getValue())
- {
- List<BundleRequirement> blameReqs = new ArrayList();
- blameReqs.add(blame.m_reqs.get(0));
-
- mergeUses(
- revision,
- revisionPkgs,
- blame.m_cap,
- blameReqs,
- revisionPkgMap,
- allCandidates,
- usesCycleMap);
- }
- }
- }
- }
-
- private void mergeCandidatePackages(
- BundleRevision current, BundleRequirement currentReq, BundleCapability candCap,
- Map<BundleRevision, Packages> revisionPkgMap,
- Candidates allCandidates, Map<BundleRevision, List<BundleCapability>> cycles)
- {
- List<BundleCapability> cycleCaps = cycles.get(current);
- if (cycleCaps == null)
- {
- cycleCaps = new ArrayList<BundleCapability>();
- cycles.put(current, cycleCaps);
- }
- if (cycleCaps.contains(candCap))
- {
- return;
- }
- cycleCaps.add(candCap);
-
- if (candCap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- mergeCandidatePackage(
- current, false, currentReq, candCap, revisionPkgMap);
- }
- else if (candCap.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
- {
-// TODO: FELIX3 - THIS NEXT LINE IS A HACK. IMPROVE HOW/WHEN WE CALCULATE EXPORTS.
- calculateExportedPackages(
- candCap.getRevision(), allCandidates, revisionPkgMap);
-
- // Get the candidate's package space to determine which packages
- // will be visible to the current revision.
- Packages candPkgs = revisionPkgMap.get(candCap.getRevision());
-
- // We have to merge all exported packages from the candidate,
- // since the current revision requires it.
- for (Entry<String, Blame> entry : candPkgs.m_exportedPkgs.entrySet())
- {
- mergeCandidatePackage(
- current,
- true,
- currentReq,
- entry.getValue().m_cap,
- revisionPkgMap);
- }
-
- // If the candidate requires any other bundles with reexport visibility,
- // then we also need to merge their packages too.
- if (candCap.getRevision().getWiring() != null)
- {
- for (BundleWire bw
- : candCap.getRevision().getWiring().getRequiredWires(null))
- {
- if (bw.getRequirement().getNamespace()
- .equals(BundleRevision.BUNDLE_NAMESPACE))
- {
- String value = bw.getRequirement()
- .getDirectives().get(Constants.VISIBILITY_DIRECTIVE);
- if ((value != null)
- && value.equals(Constants.VISIBILITY_REEXPORT))
- {
- mergeCandidatePackages(
- current,
- currentReq,
- bw.getCapability(),
- revisionPkgMap,
- allCandidates,
- cycles);
- }
- }
- }
- }
- else
- {
- for (BundleRequirement req
- : candCap.getRevision().getDeclaredRequirements(null))
- {
- if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
- {
- String value =
- req.getDirectives().get(Constants.VISIBILITY_DIRECTIVE);
- if ((value != null)
- && value.equals(Constants.VISIBILITY_REEXPORT)
- && (allCandidates.getCandidates(req) != null))
- {
- mergeCandidatePackages(
- current,
- currentReq,
- allCandidates.getCandidates(req).iterator().next(),
- revisionPkgMap,
- allCandidates,
- cycles);
- }
- }
- }
- }
- }
-
- cycles.remove(current);
- }
-
- private void mergeCandidatePackage(
- BundleRevision current, boolean requires,
- BundleRequirement currentReq, BundleCapability candCap,
- Map<BundleRevision, Packages> revisionPkgMap)
- {
- if (candCap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- // Merge the candidate capability into the revision's package space
- // for imported or required packages, appropriately.
-
- String pkgName = (String)
- candCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
-
- List blameReqs = new ArrayList();
- blameReqs.add(currentReq);
-
- Packages currentPkgs = revisionPkgMap.get(current);
-
- Map<String, List<Blame>> packages = (requires)
- ? currentPkgs.m_requiredPkgs
- : currentPkgs.m_importedPkgs;
- List<Blame> blames = packages.get(pkgName);
- if (blames == null)
- {
- blames = new ArrayList<Blame>();
- packages.put(pkgName, blames);
- }
- blames.add(new Blame(candCap, blameReqs));
-
-//dumpRevisionPkgs(current, currentPkgs);
- }
- }
-
- private void mergeUses(
- BundleRevision current, Packages currentPkgs,
- BundleCapability mergeCap, List<BundleRequirement> blameReqs,
- Map<BundleRevision, Packages> revisionPkgMap,
- Candidates allCandidates,
- Map<BundleCapability, List<BundleRevision>> cycleMap)
- {
- // If there are no uses, then just return.
- // If the candidate revision is the same as the current revision,
- // then we don't need to verify and merge the uses constraints
- // since this will happen as we build up the package space.
- if (current.equals(mergeCap.getRevision()))
- {
- return;
- }
-
- // Check for cycles.
- List<BundleRevision> list = cycleMap.get(mergeCap);
- if ((list != null) && list.contains(current))
- {
- return;
- }
- list = (list == null) ? new ArrayList<BundleRevision>() : list;
- list.add(current);
- cycleMap.put(mergeCap, list);
-
- for (BundleCapability candSourceCap : getPackageSources(mergeCap, revisionPkgMap))
- {
- for (String usedPkgName : ((BundleCapabilityImpl) candSourceCap).getUses())
- {
- Packages candSourcePkgs = revisionPkgMap.get(candSourceCap.getRevision());
- List<Blame> candSourceBlames = null;
- // Check to see if the used package is exported.
- Blame candExportedBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName);
- if (candExportedBlame != null)
- {
- candSourceBlames = new ArrayList(1);
- candSourceBlames.add(candExportedBlame);
- }
- else
- {
- // If the used package is not exported, check to see if it
- // is required.
- candSourceBlames = candSourcePkgs.m_requiredPkgs.get(usedPkgName);
- // Lastly, if the used package is not required, check to see if it
- // is imported.
- candSourceBlames = (candSourceBlames != null)
- ? candSourceBlames : candSourcePkgs.m_importedPkgs.get(usedPkgName);
- }
-
- // If the used package cannot be found, then just ignore it
- // since it has no impact.
- if (candSourceBlames == null)
- {
- continue;
- }
-
- List<Blame> usedCaps = currentPkgs.m_usedPkgs.get(usedPkgName);
- if (usedCaps == null)
- {
- usedCaps = new ArrayList<Blame>();
- currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps);
- }
- for (Blame blame : candSourceBlames)
- {
- if (blame.m_reqs != null)
- {
- List<BundleRequirement> blameReqs2 = new ArrayList(blameReqs);
- blameReqs2.add(blame.m_reqs.get(blame.m_reqs.size() - 1));
- usedCaps.add(new Blame(blame.m_cap, blameReqs2));
- mergeUses(current, currentPkgs, blame.m_cap, blameReqs2,
- revisionPkgMap, allCandidates, cycleMap);
- }
- else
- {
- usedCaps.add(new Blame(blame.m_cap, blameReqs));
- mergeUses(current, currentPkgs, blame.m_cap, blameReqs,
- revisionPkgMap, allCandidates, cycleMap);
- }
- }
- }
- }
- }
-
- private void checkPackageSpaceConsistency(
- ResolveContext rc,
- boolean isDynamicImporting,
- BundleRevision revision,
- Candidates allCandidates,
- Map<BundleRevision, Packages> revisionPkgMap,
- Map<BundleRevision, Object> resultCache)
- {
- if ((revision.getWiring() != null) && !isDynamicImporting)
- {
- return;
- }
- else if(resultCache.containsKey(revision))
- {
- return;
- }
-
- Packages pkgs = revisionPkgMap.get(revision);
-
- ResolveException rethrow = null;
- Candidates permutation = null;
- Set<BundleRequirement> mutated = null;
-
- // Check for conflicting imports from fragments.
- for (Entry<String, List<Blame>> entry : pkgs.m_importedPkgs.entrySet())
- {
- if (entry.getValue().size() > 1)
- {
- Blame sourceBlame = null;
- for (Blame blame : entry.getValue())
- {
- if (sourceBlame == null)
- {
- sourceBlame = blame;
- }
- else if (!sourceBlame.m_cap.getRevision().equals(blame.m_cap.getRevision()))
- {
- // Try to permutate the conflicting requirement.
- permutate(allCandidates, blame.m_reqs.get(0), m_importPermutations);
- // Try to permutate the source requirement.
- permutate(allCandidates, sourceBlame.m_reqs.get(0), m_importPermutations);
- // Report conflict.
- ResolveException ex = new ResolveException(
- "Uses constraint violation. Unable to resolve bundle revision "
- + revision.getSymbolicName()
- + " [" + revision
- + "] because it is exposed to package '"
- + entry.getKey()
- + "' from bundle revisions "
- + sourceBlame.m_cap.getRevision().getSymbolicName()
- + " [" + sourceBlame.m_cap.getRevision()
- + "] and "
- + blame.m_cap.getRevision().getSymbolicName()
- + " [" + blame.m_cap.getRevision()
- + "] via two dependency chains.\n\nChain 1:\n"
- + toStringBlame(rc, allCandidates, sourceBlame)
- + "\n\nChain 2:\n"
- + toStringBlame(rc, allCandidates, blame),
- revision,
- blame.m_reqs.get(0));
- m_logger.log(
- Logger.LOG_DEBUG,
- "Candidate permutation failed due to a conflict with a "
- + "fragment import; will try another if possible.",
- ex);
- throw ex;
- }
- }
- }
- }
-
- // Check if there are any uses conflicts with exported packages.
- for (Entry<String, Blame> entry : pkgs.m_exportedPkgs.entrySet())
- {
- String pkgName = entry.getKey();
- Blame exportBlame = entry.getValue();
- if (!pkgs.m_usedPkgs.containsKey(pkgName))
- {
- continue;
- }
- for (Blame usedBlame : pkgs.m_usedPkgs.get(pkgName))
- {
- if (!isCompatible(exportBlame.m_cap, usedBlame.m_cap, revisionPkgMap))
- {
- // Create a candidate permutation that eliminates all candidates
- // that conflict with existing selected candidates.
- permutation = (permutation != null)
- ? permutation
- : allCandidates.copy();
- rethrow = (rethrow != null)
- ? rethrow
- : new ResolveException(
- "Uses constraint violation. Unable to resolve bundle revision "
- + revision.getSymbolicName()
- + " [" + revision
- + "] because it exports package '"
- + pkgName
- + "' and is also exposed to it from bundle revision "
- + usedBlame.m_cap.getRevision().getSymbolicName()
- + " [" + usedBlame.m_cap.getRevision()
- + "] via the following dependency chain:\n\n"
- + toStringBlame(rc, allCandidates, usedBlame),
- null,
- null);
-
- mutated = (mutated != null)
- ? mutated
- : new HashSet<BundleRequirement>();
-
- for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
- {
- BundleRequirement req = usedBlame.m_reqs.get(reqIdx);
-
- // If we've already permutated this requirement in another
- // uses constraint, don't permutate it again just continue
- // with the next uses constraint.
- if (mutated.contains(req))
- {
- break;
- }
-
- // See if we can permutate the candidates for blamed
- // requirement; there may be no candidates if the revision
- // associated with the requirement is already resolved.
- List<BundleCapability> candidates = permutation.getCandidates(req);
- if ((candidates != null) && (candidates.size() > 1))
- {
- mutated.add(req);
- // Remove the conflicting candidate.
- candidates.remove(0);
- // Continue with the next uses constraint.
- break;
- }
- }
- }
- }
-
- if (rethrow != null)
- {
- if (mutated.size() > 0)
- {
- m_usesPermutations.add(permutation);
- }
- m_logger.log(
- Logger.LOG_DEBUG,
- "Candidate permutation failed due to a conflict between "
- + "an export and import; will try another if possible.",
- rethrow);
- throw rethrow;
- }
- }
-
- // Check if there are any uses conflicts with imported packages.
- for (Entry<String, List<Blame>> entry : pkgs.m_importedPkgs.entrySet())
- {
- for (Blame importBlame : entry.getValue())
- {
- String pkgName = entry.getKey();
- if (!pkgs.m_usedPkgs.containsKey(pkgName))
- {
- continue;
- }
- for (Blame usedBlame : pkgs.m_usedPkgs.get(pkgName))
- {
- if (!isCompatible(importBlame.m_cap, usedBlame.m_cap, revisionPkgMap))
- {
- // Create a candidate permutation that eliminates any candidates
- // that conflict with existing selected candidates.
- permutation = (permutation != null)
- ? permutation
- : allCandidates.copy();
- rethrow = (rethrow != null)
- ? rethrow
- : new ResolveException(
- "Uses constraint violation. Unable to resolve bundle revision "
- + revision.getSymbolicName()
- + " [" + revision
- + "] because it is exposed to package '"
- + pkgName
- + "' from bundle revisions "
- + importBlame.m_cap.getRevision().getSymbolicName()
- + " [" + importBlame.m_cap.getRevision()
- + "] and "
- + usedBlame.m_cap.getRevision().getSymbolicName()
- + " [" + usedBlame.m_cap.getRevision()
- + "] via two dependency chains.\n\nChain 1:\n"
- + toStringBlame(rc, allCandidates, importBlame)
- + "\n\nChain 2:\n"
- + toStringBlame(rc, allCandidates, usedBlame),
- null,
- null);
-
- mutated = (mutated != null)
- ? mutated
- : new HashSet();
-
- for (int reqIdx = usedBlame.m_reqs.size() - 1; reqIdx >= 0; reqIdx--)
- {
- BundleRequirement req = usedBlame.m_reqs.get(reqIdx);
-
- // If we've already permutated this requirement in another
- // uses constraint, don't permutate it again just continue
- // with the next uses constraint.
- if (mutated.contains(req))
- {
- break;
- }
-
- // See if we can permutate the candidates for blamed
- // requirement; there may be no candidates if the revision
- // associated with the requirement is already resolved.
- List<BundleCapability> candidates = permutation.getCandidates(req);
- if ((candidates != null) && (candidates.size() > 1))
- {
- mutated.add(req);
- // Remove the conflicting candidate.
- candidates.remove(0);
- // Continue with the next uses constraint.
- break;
- }
- }
- }
- }
-
- // If there was a uses conflict, then we should add a uses
- // permutation if we were able to permutate any candidates.
- // Additionally, we should try to push an import permutation
- // for the original import to force a backtracking on the
- // original candidate decision if no viable candidate is found
- // for the conflicting uses constraint.
- if (rethrow != null)
- {
- // Add uses permutation if we mutated any candidates.
- if (mutated.size() > 0)
- {
- m_usesPermutations.add(permutation);
- }
-
- // Try to permutate the candidate for the original
- // import requirement; only permutate it if we haven't
- // done so already.
- BundleRequirement req = importBlame.m_reqs.get(0);
- if (!mutated.contains(req))
- {
- // Since there may be lots of uses constraint violations
- // with existing import decisions, we may end up trying
- // to permutate the same import a lot of times, so we should
- // try to check if that the case and only permutate it once.
- permutateIfNeeded(allCandidates, req, m_importPermutations);
- }
-
- m_logger.log(
- Logger.LOG_DEBUG,
- "Candidate permutation failed due to a conflict between "
- + "imports; will try another if possible.",
- rethrow);
- throw rethrow;
- }
- }
- }
-
- resultCache.put(revision, Boolean.TRUE);
-
- // Now check the consistency of all revisions on which the
- // current revision depends. Keep track of the current number
- // of permutations so we know if the lower level check was
- // able to create a permutation or not in the case of failure.
- int permCount = m_usesPermutations.size() + m_importPermutations.size();
- for (Entry<String, List<Blame>> entry : pkgs.m_importedPkgs.entrySet())
- {
- for (Blame importBlame : entry.getValue())
- {
- if (!revision.equals(importBlame.m_cap.getRevision()))
- {
- try
- {
- checkPackageSpaceConsistency(
- rc, false, importBlame.m_cap.getRevision(),
- allCandidates, revisionPkgMap, resultCache);
- }
- catch (ResolveException ex)
- {
- // If the lower level check didn't create any permutations,
- // then we should create an import permutation for the
- // requirement with the dependency on the failing revision
- // to backtrack on our current candidate selection.
- if (permCount == (m_usesPermutations.size() + m_importPermutations.size()))
- {
- BundleRequirement req = importBlame.m_reqs.get(0);
- permutate(allCandidates, req, m_importPermutations);
- }
- throw ex;
- }
- }
- }
- }
- }
-
- private static void permutate(
- Candidates allCandidates, BundleRequirement req, List<Candidates> permutations)
- {
- List<BundleCapability> candidates = allCandidates.getCandidates(req);
- if (candidates.size() > 1)
- {
- Candidates perm = allCandidates.copy();
- candidates = perm.getCandidates(req);
- candidates.remove(0);
- permutations.add(perm);
- }
- }
-
- private static void permutateIfNeeded(
- Candidates allCandidates, BundleRequirement req, List<Candidates> permutations)
- {
- List<BundleCapability> candidates = allCandidates.getCandidates(req);
- if (candidates.size() > 1)
- {
- // Check existing permutations to make sure we haven't
- // already permutated this requirement. This check for
- // duplicate permutations is simplistic. It assumes if
- // there is any permutation that contains a different
- // initial candidate for the requirement in question,
- // then it has already been permutated.
- boolean permutated = false;
- for (Candidates existingPerm : permutations)
- {
- List<BundleCapability> existingPermCands = existingPerm.getCandidates(req);
- if (!existingPermCands.get(0).equals(candidates.get(0)))
- {
- permutated = true;
- }
- }
- // If we haven't already permutated the existing
- // import, do so now.
- if (!permutated)
- {
- permutate(allCandidates, req, permutations);
- }
- }
- }
-
- private static void calculateExportedPackages(
- BundleRevision revision,
- Candidates allCandidates,
- Map<BundleRevision, Packages> revisionPkgMap)
- {
- Packages packages = revisionPkgMap.get(revision);
- if (packages != null)
- {
- return;
- }
- packages = new Packages(revision);
-
- // Get all exported packages.
- List<BundleCapability> caps = (revision.getWiring() != null)
- ? revision.getWiring().getCapabilities(null)
- : revision.getDeclaredCapabilities(null);
- Map<String, BundleCapability> exports =
- new HashMap<String, BundleCapability>(caps.size());
- for (BundleCapability cap : caps)
- {
- if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- if (!cap.getRevision().equals(revision))
- {
- cap = new WrappedCapability(revision, (BundleCapabilityImpl) cap);
- }
- exports.put(
- (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
- cap);
- }
- }
- // Remove substitutable exports that were imported.
- // For resolved revisions BundleWiring.getCapabilities()
- // already excludes imported substitutable exports, but
- // for resolving revisions we must look in the candidate
- // map to determine which exports are substitutable.
- if (!exports.isEmpty())
- {
- if (revision.getWiring() == null)
- {
- for (BundleRequirement req : revision.getDeclaredRequirements(null))
- {
- if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- List<BundleCapability> cands = allCandidates.getCandidates(req);
- if ((cands != null) && !cands.isEmpty())
- {
- String pkgName = (String) cands.get(0)
- .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
- exports.remove(pkgName);
- }
- }
- }
- }
-
- // Add all non-substituted exports to the revisions's package space.
- for (Entry<String, BundleCapability> entry : exports.entrySet())
- {
- packages.m_exportedPkgs.put(
- entry.getKey(), new Blame(entry.getValue(), null));
- }
- }
-
- revisionPkgMap.put(revision, packages);
- }
-
- private boolean isCompatible(
- BundleCapability currentCap, BundleCapability candCap,
- Map<BundleRevision, Packages> revisionPkgMap)
- {
- if ((currentCap != null) && (candCap != null))
- {
- if (currentCap.equals(candCap))
- {
- return true;
- }
-
- List<BundleCapability> currentSources =
- getPackageSources(
- currentCap,
- revisionPkgMap);
- List<BundleCapability> candSources =
- getPackageSources(
- candCap,
- revisionPkgMap);
-
- return currentSources.containsAll(candSources)
- || candSources.containsAll(currentSources);
- }
- return true;
- }
-
- private Map<BundleCapability, List<BundleCapability>> m_packageSourcesCache
- = new HashMap();
-
- private List<BundleCapability> getPackageSources(
- BundleCapability cap, Map<BundleRevision, Packages> revisionPkgMap)
- {
- if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- List<BundleCapability> sources = m_packageSourcesCache.get(cap);
- if (sources == null)
- {
- sources = getPackageSourcesInternal(
- cap, revisionPkgMap, new ArrayList(), new HashSet());
- m_packageSourcesCache.put(cap, sources);
- }
- return sources;
- }
-
- if (!((BundleCapabilityImpl) cap).getUses().isEmpty())
- {
- List<BundleCapability> caps = new ArrayList<BundleCapability>(1);
- caps.add(cap);
- return caps;
- }
-
- return Collections.EMPTY_LIST;
- }
-
- private static List<BundleCapability> getPackageSourcesInternal(
- BundleCapability cap, Map<BundleRevision, Packages> revisionPkgMap,
- List<BundleCapability> sources, Set<BundleCapability> cycleMap)
- {
- if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- if (cycleMap.contains(cap))
- {
- return sources;
- }
- cycleMap.add(cap);
-
- // Get the package name associated with the capability.
- String pkgName = cap.getAttributes()
- .get(BundleRevision.PACKAGE_NAMESPACE).toString();
-
- // Since a revision can export the same package more than once, get
- // all package capabilities for the specified package name.
- List<BundleCapability> caps = (cap.getRevision().getWiring() != null)
- ? cap.getRevision().getWiring().getCapabilities(null)
- : cap.getRevision().getDeclaredCapabilities(null);
- for (BundleCapability sourceCap : caps)
- {
- if (sourceCap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
- && sourceCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
- {
- // Since capabilities may come from fragments, we need to check
- // for that case and wrap them.
- if (!cap.getRevision().equals(sourceCap.getRevision()))
- {
- sources.add(
- new WrappedCapability(cap.getRevision(), (BundleCapabilityImpl) sourceCap));
- }
- else
- {
- sources.add(sourceCap);
- }
- }
- }
-
- // Then get any addition sources for the package from required bundles.
- Packages pkgs = revisionPkgMap.get(cap.getRevision());
- List<Blame> required = pkgs.m_requiredPkgs.get(pkgName);
- if (required != null)
- {
- for (Blame blame : required)
- {
- getPackageSourcesInternal(blame.m_cap, revisionPkgMap, sources, cycleMap);
- }
- }
- }
-
- return sources;
- }
-
- private static BundleRevision getDeclaringBundleRevision(BundleRevision br)
- {
- if (br instanceof WrappedRevision)
- {
- return ((WrappedRevision) br).getHost();
- }
- return br;
- }
-
- private static BundleCapability getDeclaredCapability(BundleCapability c)
- {
- if (c instanceof HostedCapability)
- {
- return ((HostedCapability) c).getDeclaredCapability();
- }
- return c;
- }
-
- private static BundleRequirement getDeclaredRequirement(BundleRequirement r)
- {
- if (r instanceof WrappedRequirement)
- {
- return ((WrappedRequirement) r).getOriginalRequirement();
- }
- return r;
- }
-
- private static Map<BundleRevision, List<ResolverWire>> populateWireMap(
- BundleRevision revision, Map<BundleRevision, Packages> revisionPkgMap,
- Map<BundleRevision, List<ResolverWire>> wireMap,
- Candidates allCandidates)
- {
- BundleRevision unwrappedRevision = getDeclaringBundleRevision(revision);
- if ((unwrappedRevision.getWiring() == null)
- && !wireMap.containsKey(unwrappedRevision))
- {
- wireMap.put(unwrappedRevision, (List<ResolverWire>) Collections.EMPTY_LIST);
-
- List<ResolverWire> packageWires = new ArrayList<ResolverWire>();
- List<ResolverWire> bundleWires = new ArrayList<ResolverWire>();
- List<ResolverWire> capabilityWires = new ArrayList<ResolverWire>();
-
- for (BundleRequirement req : revision.getDeclaredRequirements(null))
- {
- List<BundleCapability> cands = allCandidates.getCandidates(req);
- if ((cands != null) && (cands.size() > 0))
- {
- BundleCapability cand = cands.get(0);
- // Ignore revisions that import themselves.
- if (!revision.equals(cand.getRevision()))
- {
- if (cand.getRevision().getWiring() == null)
- {
- populateWireMap(cand.getRevision(),
- revisionPkgMap, wireMap, allCandidates);
- }
- Packages candPkgs = revisionPkgMap.get(cand.getRevision());
- ResolverWire wire = new ResolverWireImpl(
- unwrappedRevision,
- getDeclaredRequirement(req),
- getDeclaringBundleRevision(cand.getRevision()),
- getDeclaredCapability(cand));
- if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- packageWires.add(wire);
- }
- else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
- {
- bundleWires.add(wire);
- }
- else
- {
- capabilityWires.add(wire);
- }
- }
- }
- }
-
- // Combine package wires with require wires last.
- packageWires.addAll(bundleWires);
- packageWires.addAll(capabilityWires);
- wireMap.put(unwrappedRevision, packageWires);
-
- // Add host wire for any fragments.
- if (revision instanceof WrappedRevision)
- {
- List<BundleRevision> fragments = ((WrappedRevision) revision).getFragments();
- for (BundleRevision fragment : fragments)
- {
- List<ResolverWire> hostWires = wireMap.get(fragment);
- if (hostWires == null)
- {
- hostWires = new ArrayList<ResolverWire>();
- wireMap.put(fragment, hostWires);
- }
- hostWires.add(
- new ResolverWireImpl(
- getDeclaringBundleRevision(fragment),
- fragment.getDeclaredRequirements(
- BundleRevision.HOST_NAMESPACE).get(0),
- unwrappedRevision,
- unwrappedRevision.getDeclaredCapabilities(
- BundleRevision.HOST_NAMESPACE).get(0)));
- }
- }
- }
-
- return wireMap;
- }
-
- private static Map<BundleRevision, List<ResolverWire>> populateDynamicWireMap(
- BundleRevision revision, String pkgName, Map<BundleRevision, Packages> revisionPkgMap,
- Map<BundleRevision, List<ResolverWire>> wireMap, Candidates allCandidates)
- {
- wireMap.put(revision, (List<ResolverWire>) Collections.EMPTY_LIST);
-
- List<ResolverWire> packageWires = new ArrayList<ResolverWire>();
-
- BundleRequirement dynReq = null;
- BundleCapability dynCand = null;
- for (BundleRequirement req
- : Util.getDynamicRequirements(revision.getWiring().getRequirements(null)))
- {
- // Get the candidates for the current dynamic requirement.
- List<BundleCapability> candCaps = allCandidates.getCandidates(req);
- // Optional requirements may not have any candidates.
- if ((candCaps == null) || candCaps.isEmpty())
- {
- continue;
- }
-
- // Record the dynamic requirement.
- dynReq = req;
- dynCand = candCaps.get(0);
-
- // Can only dynamically import one at a time, so break
- // out of the loop after the first.
- break;
- }
-
- if (dynReq != null)
- {
- if (dynCand.getRevision().getWiring() == null)
- {
- populateWireMap(dynCand.getRevision(), revisionPkgMap, wireMap,
- allCandidates);
- }
-
- packageWires.add(
- new ResolverWireImpl(
- revision,
- dynReq,
- getDeclaringBundleRevision(dynCand.getRevision()),
- getDeclaredCapability(dynCand)));
- }
-
- wireMap.put(revision, packageWires);
-
- return wireMap;
- }
-
- private static void dumpRevisionPkgMap(Map<BundleRevision, Packages> revisionPkgMap)
- {
- System.out.println("+++BUNDLE REVISION PKG MAP+++");
- for (Entry<BundleRevision, Packages> entry : revisionPkgMap.entrySet())
- {
- dumpRevisionPkgs(entry.getKey(), entry.getValue());
- }
- }
-
- private static void dumpRevisionPkgs(BundleRevision revision, Packages packages)
- {
- System.out.println(revision
- + " (" + ((revision.getWiring() != null) ? "RESOLVED)" : "UNRESOLVED)"));
- System.out.println(" EXPORTED");
- for (Entry<String, Blame> entry : packages.m_exportedPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- System.out.println(" IMPORTED");
- for (Entry<String, List<Blame>> entry : packages.m_importedPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- System.out.println(" REQUIRED");
- for (Entry<String, List<Blame>> entry : packages.m_requiredPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- System.out.println(" USED");
- for (Entry<String, List<Blame>> entry : packages.m_usedPkgs.entrySet())
- {
- System.out.println(" " + entry.getKey() + " - " + entry.getValue());
- }
- }
-
- private static String toStringBlame(
- ResolveContext rc, Candidates allCandidates, Blame blame)
- {
- StringBuffer sb = new StringBuffer();
- if ((blame.m_reqs != null) && !blame.m_reqs.isEmpty())
- {
- for (int i = 0; i < blame.m_reqs.size(); i++)
- {
- BundleRequirement req = blame.m_reqs.get(i);
- sb.append(" ");
- sb.append(req.getRevision().getSymbolicName());
- sb.append(" [");
- sb.append(req.getRevision().toString());
- sb.append("]\n");
- if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- sb.append(" import: ");
- }
- else
- {
- sb.append(" require: ");
- }
- sb.append(((BundleRequirementImpl) req).getFilter().toString());
- sb.append("\n |");
- if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- sb.append("\n export: ");
- }
- else
- {
- sb.append("\n provide: ");
- }
- if ((i + 1) < blame.m_reqs.size())
- {
- BundleCapability cap = getSatisfyingCapability(
- rc,
- allCandidates,
- blame.m_reqs.get(i));
- if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- sb.append(BundleRevision.PACKAGE_NAMESPACE);
- sb.append("=");
- sb.append(cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString());
- BundleCapability usedCap =
- getSatisfyingCapability(
- rc,
- allCandidates,
- blame.m_reqs.get(i + 1));
- sb.append("; uses:=");
- sb.append(usedCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
- }
- else
- {
- sb.append(cap);
- }
- sb.append("\n");
- }
- else
- {
- BundleCapability export = getSatisfyingCapability(
- rc,
- allCandidates,
- blame.m_reqs.get(i));
- sb.append(export.getNamespace());
- sb.append("=");
- sb.append(export.getAttributes().get(export.getNamespace()).toString());
- if (export.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
- && !export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
- .equals(blame.m_cap.getAttributes().get(
- BundleRevision.PACKAGE_NAMESPACE)))
- {
- sb.append("; uses:=");
- sb.append(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
- sb.append("\n export: ");
- sb.append(BundleRevision.PACKAGE_NAMESPACE);
- sb.append("=");
- sb.append(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString());
- }
- sb.append("\n ");
- sb.append(blame.m_cap.getRevision().getSymbolicName());
- sb.append(" [");
- sb.append(blame.m_cap.getRevision().toString());
- sb.append("]");
- }
- }
- }
- else
- {
- sb.append(blame.m_cap.getRevision().toString());
- }
- return sb.toString();
- }
-
- private static BundleCapability getSatisfyingCapability(
- ResolveContext rc, Candidates allCandidates, BundleRequirement req)
- {
- BundleCapability cap = null;
-
- // If the requiring revision is not resolved, then check in the
- // candidate map for its matching candidate.
- List<BundleCapability> cands = allCandidates.getCandidates(req);
- if (cands != null)
- {
- cap = cands.get(0);
- }
- // Otherwise, if the requiring revision is resolved then check
- // in its wires for the capability satisfying the requirement.
- else if (rc.getWirings().containsKey(req.getRevision()))
- {
- List<BundleWire> wires = rc.getWirings().get(req.getRevision()).getRequiredWires(null);
- req = getDeclaredRequirement(req);
- for (BundleWire w : wires)
- {
- if (w.getRequirement().equals(req))
- {
-// TODO: RESOLVER - This is not 100% correct, since requirements for
-// dynamic imports with wildcards will reside on many wires and
-// this code only finds the first one, not necessarily the correct
-// one. This is only used for the diagnostic message, but it still
-// could confuse the user.
- cap = w.getCapability();
- break;
- }
- }
- }
-
- return cap;
- }
-
- private static class Packages
- {
- private final BundleRevision m_revision;
- public final Map<String, Blame> m_exportedPkgs = new HashMap();
- public final Map<String, List<Blame>> m_importedPkgs = new HashMap();
- public final Map<String, List<Blame>> m_requiredPkgs = new HashMap();
- public final Map<String, List<Blame>> m_usedPkgs = new HashMap();
- public boolean m_isCalculated = false;
-
- public Packages(BundleRevision revision)
- {
- m_revision = revision;
- }
- }
-
- private static class Blame
- {
- public final BundleCapability m_cap;
- public final List<BundleRequirement> m_reqs;
-
- public Blame(BundleCapability cap, List<BundleRequirement> reqs)
- {
- m_cap = cap;
- m_reqs = reqs;
- }
-
- @Override
- public String toString()
- {
- return m_cap.getRevision()
- + "." + m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
- + (((m_reqs == null) || m_reqs.isEmpty())
- ? " NO BLAME"
- : " BLAMED ON " + m_reqs);
- }
-
- @Override
- public boolean equals(Object o)
- {
- return (o instanceof Blame) && m_reqs.equals(((Blame) o).m_reqs)
- && m_cap.equals(((Blame) o).m_cap);
- }
- }
-}
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverWire.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverWire.java
deleted file mode 100644
index 69162b9..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverWire.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.resolver;
-
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-
-public interface ResolverWire
-{
- /**
- * Returns the importing bundle revision.
- * @return The importing bundle revision.
- **/
- public BundleRevision getRequirer();
- /**
- * Returns the associated requirement from the importing bundle revision
- * that resulted in the creation of this wire.
- * @return
- **/
- public BundleRequirement getRequirement();
- /**
- * Returns the exporting bundle revision.
- * @return The exporting bundle revision.
- **/
- public BundleRevision getProvider();
- /**
- * Returns the associated capability from the exporting bundle revision
- * that satisfies the requirement of the importing bundle revision.
- * @return
- **/
- public BundleCapability getCapability();
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverWireImpl.java b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverWireImpl.java
deleted file mode 100644
index 4f8420f..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverWireImpl.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.resolver;
-
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-
-class ResolverWireImpl implements ResolverWire
-{
- private final BundleRevision m_requirer;
- private final BundleRequirement m_req;
- private final BundleRevision m_provider;
- private final BundleCapability m_cap;
-
- public ResolverWireImpl(
- BundleRevision requirer, BundleRequirement req,
- BundleRevision provider, BundleCapability cap)
- {
- m_requirer = requirer;
- m_req = req;
- m_provider = provider;
- m_cap = cap;
- }
-
- public BundleRevision getRequirer()
- {
- return m_requirer;
- }
-
- public BundleRequirement getRequirement()
- {
- return m_req;
- }
-
- public BundleRevision getProvider()
- {
- return m_provider;
- }
-
- public BundleCapability getCapability()
- {
- return m_cap;
- }
-
- public String toString()
- {
- return m_req
- + " -> "
- + "[" + m_provider + "]";
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java b/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java
deleted file mode 100644
index e64b559..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-
-public class ShadowList<T> implements List<T>
-{
- private final List<T> m_original;
- private final List<T> m_shadow;
-
- public ShadowList(List<T> original)
- {
- m_original = original;
- m_shadow = new ArrayList<T>(original);
- }
-
- public List<T> getOriginal()
- {
- return m_original;
- }
-
- public int size()
- {
- return m_shadow.size();
- }
-
- public boolean isEmpty()
- {
- return m_shadow.isEmpty();
- }
-
- public boolean contains(Object o)
- {
- return m_shadow.contains(o);
- }
-
- public Iterator<T> iterator()
- {
- return m_shadow.iterator();
- }
-
- public Object[] toArray()
- {
- return m_shadow.toArray();
- }
-
- public <T> T[] toArray(T[] ts)
- {
- return m_shadow.toArray(ts);
- }
-
- public boolean add(T e)
- {
- return m_shadow.add(e);
- }
-
- public boolean remove(Object o)
- {
- return m_shadow.remove(o);
- }
-
- public boolean containsAll(Collection<?> clctn)
- {
- return m_shadow.containsAll(clctn);
- }
-
- public boolean addAll(Collection<? extends T> clctn)
- {
- return m_shadow.addAll(clctn);
- }
-
- public boolean addAll(int i, Collection<? extends T> clctn)
- {
- return m_shadow.addAll(i, clctn);
- }
-
- public boolean removeAll(Collection<?> clctn)
- {
- return m_shadow.removeAll(clctn);
- }
-
- public boolean retainAll(Collection<?> clctn)
- {
- return m_shadow.retainAll(clctn);
- }
-
- public void clear()
- {
- m_shadow.clear();
- }
-
- public T get(int i)
- {
- return m_shadow.get(i);
- }
-
- public T set(int i, T e)
- {
- return m_shadow.set(i, e);
- }
-
- public void add(int i, T e)
- {
- m_shadow.add(i, e);
- }
-
- public T remove(int i)
- {
- return m_shadow.remove(i);
- }
-
- public int indexOf(Object o)
- {
- return m_shadow.indexOf(o);
- }
-
- public int lastIndexOf(Object o)
- {
- return m_shadow.lastIndexOf(o);
- }
-
- public ListIterator<T> listIterator()
- {
- return m_shadow.listIterator();
- }
-
- public ListIterator<T> listIterator(int i)
- {
- return m_shadow.listIterator(i);
- }
-
- public List<T> subList(int i, int i1)
- {
- return m_shadow.subList(i, i1);
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java b/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java
deleted file mode 100644
index 89b2984..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.Map;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRevision;
-
-class SimpleHostedCapability implements HostedCapability
-{
- private final BundleRevision m_host;
- private final BundleCapability m_cap;
-
- SimpleHostedCapability(BundleRevision host, BundleCapability cap)
- {
- m_host = host;
- m_cap = cap;
- }
-
- public BundleRevision getResource()
- {
- return m_host;
- }
-
- public BundleRevision getRevision()
- {
- return m_host;
- }
-
- public BundleCapability getDeclaredCapability()
- {
- return m_cap;
- }
-
- public String getNamespace()
- {
- return m_cap.getNamespace();
- }
-
- public Map<String, String> getDirectives()
- {
- return m_cap.getDirectives();
- }
-
- public Map<String, Object> getAttributes()
- {
- return m_cap.getAttributes();
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java
deleted file mode 100644
index ee159ff..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2012). All Rights Reserved.
- *
- * 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.resolver;
-
-import java.util.List;
-import java.util.Map;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.resource.Resource;
-
-public class WrappedCapability extends BundleCapabilityImpl implements HostedCapability
-{
- private final BundleRevision m_host;
- private final BundleCapabilityImpl m_cap;
-
- public WrappedCapability(BundleRevision host, BundleCapabilityImpl cap)
- {
- super(host, cap.getNamespace(), cap.getDirectives(), cap.getAttributes());
- m_host = host;
- m_cap = cap;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj == null)
- {
- return false;
- }
- if (getClass() != obj.getClass())
- {
- return false;
- }
- final WrappedCapability other = (WrappedCapability) obj;
- if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host)))
- {
- return false;
- }
- if (m_cap != other.m_cap && (m_cap == null || !m_cap.equals(other.m_cap)))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode()
- {
- int hash = 7;
- hash = 37 * hash + (m_host != null ? m_host.hashCode() : 0);
- hash = 37 * hash + (m_cap != null ? m_cap.hashCode() : 0);
- return hash;
- }
-
- public BundleCapability getDeclaredCapability()
- {
- return m_cap;
- }
-
- @Override
- public BundleRevision getResource()
- {
- return m_host;
- }
-
- @Override
- public BundleRevision getRevision()
- {
- return m_host;
- }
-
- @Override
- public String getNamespace()
- {
- return m_cap.getNamespace();
- }
-
- @Override
- public Map<String, String> getDirectives()
- {
- return m_cap.getDirectives();
- }
-
- @Override
- public Map<String, Object> getAttributes()
- {
- return m_cap.getAttributes();
- }
-
- @Override
- public List<String> getUses()
- {
- return m_cap.getUses();
- }
-
- @Override
- public String toString()
- {
- if (m_host == null)
- {
- return getAttributes().toString();
- }
- if (getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- return "[" + m_host + "] "
- + getNamespace()
- + "; "
- + getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
- }
- return "[" + m_host + "] " + getNamespace() + "; " + getAttributes();
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
deleted file mode 100644
index c0d15e0..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.Map;
-import org.apache.felix.framework.capabilityset.SimpleFilter;
-import org.apache.felix.framework.wiring.BundleRequirementImpl;
-import org.osgi.framework.wiring.BundleRevision;
-
-public class WrappedRequirement extends BundleRequirementImpl
-{
- private final BundleRevision m_host;
- private final BundleRequirementImpl m_req;
-
- public WrappedRequirement(BundleRevision host, BundleRequirementImpl req)
- {
- super(host, req.getNamespace(), req.getDirectives(), req.getAttributes());
- m_host = host;
- m_req = req;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj == null)
- {
- return false;
- }
- if (getClass() != obj.getClass())
- {
- return false;
- }
- final WrappedRequirement other = (WrappedRequirement) obj;
- if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host)))
- {
- return false;
- }
- if (m_req != other.m_req && (m_req == null || !m_req.equals(other.m_req)))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode()
- {
- int hash = 7;
- hash = 37 * hash + (m_host != null ? m_host.hashCode() : 0);
- hash = 37 * hash + (m_req != null ? m_req.hashCode() : 0);
- return hash;
- }
-
- public BundleRequirementImpl getOriginalRequirement()
- {
- return m_req;
- }
-
- @Override
- public BundleRevision getRevision()
- {
- return m_host;
- }
-
- @Override
- public String getNamespace()
- {
- return m_req.getNamespace();
- }
-
- @Override
- public SimpleFilter getFilter()
- {
- return m_req.getFilter();
- }
-
- @Override
- public boolean isOptional()
- {
- return m_req.isOptional();
- }
-
- @Override
- public Map<String, String> getDirectives()
- {
- return m_req.getDirectives();
- }
-
- @Override
- public Map<String, Object> getAttributes()
- {
- return m_req.getAttributes();
- }
-
- @Override
- public String toString()
- {
- return "[" + m_host + "] " + getNamespace() + "; " + getFilter().toString();
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
deleted file mode 100644
index fa4ab5d..0000000
--- a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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.resolver;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.felix.framework.util.ImmutableList;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-import org.apache.felix.framework.wiring.BundleRequirementImpl;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-
-class WrappedRevision implements BundleRevision
-{
- private final BundleRevision m_host;
- private final List<BundleRevision> m_fragments;
- private List<BundleCapability> m_cachedCapabilities = null;
- private List<BundleRequirement> m_cachedRequirements = null;
-
- public WrappedRevision(BundleRevision host, List<BundleRevision> fragments)
- {
- m_host = host;
- m_fragments = fragments;
- }
-
- public BundleRevision getHost()
- {
- return m_host;
- }
-
- public List<BundleRevision> getFragments()
- {
- return m_fragments;
- }
-
- public String getSymbolicName()
- {
- return m_host.getSymbolicName();
- }
-
- public Version getVersion()
- {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- public List<Capability> getCapabilities(String namespace)
- {
- return asCapabilityList(getDeclaredCapabilities(namespace));
- }
-
- private static List<Capability> asCapabilityList(List caps)
- {
- return (List<Capability>) caps;
- }
-
- public List<BundleCapability> getDeclaredCapabilities(String namespace)
- {
- if (m_cachedCapabilities == null)
- {
- List<BundleCapability> caps = new ArrayList<BundleCapability>();
-
- // Wrap host capabilities.
- for (BundleCapability cap : m_host.getDeclaredCapabilities(null))
- {
- caps.add(new WrappedCapability(this, (BundleCapabilityImpl) cap));
- }
-
- // Wrap fragment capabilities.
- if (m_fragments != null)
- {
- for (BundleRevision fragment : m_fragments)
- {
- for (BundleCapability cap : fragment.getDeclaredCapabilities(null))
- {
-// TODO: OSGi R4.4 - OSGi R4.4 may introduce an identity capability, if so
-// that will need to be excluded from here.
- caps.add(new WrappedCapability(this, (BundleCapabilityImpl) cap));
- }
- }
- }
- m_cachedCapabilities = ImmutableList.newInstance(caps);
- }
- return m_cachedCapabilities;
- }
-
- public List<Requirement> getRequirements(String namespace)
- {
- return asRequirementList(getDeclaredRequirements(namespace));
- }
-
- private static List<Requirement> asRequirementList(List reqs)
- {
- return (List<Requirement>) reqs;
- }
-
- public List<BundleRequirement> getDeclaredRequirements(String namespace)
- {
- if (m_cachedRequirements == null)
- {
- List<BundleRequirement> reqs = new ArrayList<BundleRequirement>();
-
- // Wrap host requirements.
- for (BundleRequirement req : m_host.getDeclaredRequirements(null))
- {
- reqs.add(new WrappedRequirement(this, (BundleRequirementImpl) req));
- }
-
- // Wrap fragment requirements.
- if (m_fragments != null)
- {
- for (BundleRevision fragment : m_fragments)
- {
- for (BundleRequirement req : fragment.getDeclaredRequirements(null))
- {
- if (!req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
- {
- reqs.add(new WrappedRequirement(this, (BundleRequirementImpl) req));
- }
- }
- }
- }
- m_cachedRequirements = ImmutableList.newInstance(reqs);
- }
- return m_cachedRequirements;
- }
-
- public int getTypes()
- {
- return m_host.getTypes();
- }
-
- public BundleWiring getWiring()
- {
- return null;
- }
-
- public Bundle getBundle()
- {
- return m_host.getBundle();
- }
-
- @Override
- public String toString()
- {
- return m_host.toString();
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/Util.java b/framework/src/main/java/org/apache/felix/framework/util/Util.java
index 8128aa1..3298a27 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/Util.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/Util.java
@@ -18,7 +18,11 @@
*/
package org.apache.felix.framework.util;
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
@@ -31,9 +35,6 @@
import java.util.Set;
import org.apache.felix.framework.Logger;
-import org.apache.felix.framework.capabilityset.CapabilitySet;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-import org.apache.felix.framework.wiring.BundleRequirementImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -42,6 +43,7 @@
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.resource.Resource;
public class Util
{
@@ -665,7 +667,7 @@
{
if (entry.getKey().equalsIgnoreCase(Constants.SINGLETON_DIRECTIVE))
{
- return Boolean.valueOf((String) entry.getValue());
+ return Boolean.valueOf(entry.getValue());
}
}
// Can only have one bundle capability, so break.
@@ -687,6 +689,14 @@
return ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) > 0);
}
+ public static boolean isFragment(Resource resource)
+ {
+ if (resource instanceof BundleRevision)
+ return isFragment((BundleRevision) resource);
+ else
+ return false;
+ }
+
public static List<BundleRevision> getFragments(BundleWiring wiring)
{
List<BundleRevision> fragments = Collections.EMPTY_LIST;