Refactor internal resolver APIs to align with upcoming OSGi resolver spec. (FELIX-3394)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1300618 13f79535-47bb-0310-9956-ffa450edef68
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 ce063cb..287087e 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -1928,7 +1928,7 @@
{
try
{
- m_revision.getSecureAction()
+ BundleRevisionImpl.getSecureAction()
.invokeWeavingHook(wh, wci);
}
catch (Throwable th)
@@ -2531,7 +2531,7 @@
BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(
revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
- Set<BundleCapability> exporters = resolver.getCandidates(req, false);
+ List<BundleCapability> exporters = resolver.findProviders(req, false);
BundleRevision provider = null;
try
@@ -2570,7 +2570,7 @@
BundleRevision.PACKAGE_NAMESPACE, (Object) pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(
revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
- Set<BundleCapability> exports = resolver.getCandidates(req, false);
+ List<BundleCapability> exports = resolver.findProviders(req, false);
if (exports.size() > 0)
{
boolean classpath = false;
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 46a1162..dc1e144 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -3564,7 +3564,7 @@
BundleRevision.PACKAGE_NAMESPACE,
Collections.EMPTY_MAP,
attrs);
- Set<BundleCapability> exports = m_resolver.getCandidates(req, false);
+ List<BundleCapability> exports = m_resolver.findProviders(req, false);
// We only want resolved capabilities.
for (Iterator<BundleCapability> it = exports.iterator(); it.hasNext(); )
diff --git a/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java b/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
new file mode 100644
index 0000000..c3a136f
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/ResolveContextImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+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.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
+
+/**
+ *
+ * @author rickhall
+ */
+public class ResolveContextImpl extends ResolveContext
+{
+ private final StatefulResolver m_state;
+ private final Map<BundleRevision, BundleWiring> m_wirings;
+ 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,
+ Collection<BundleRevision> mandatory, Collection<BundleRevision> optional,
+ Collection<BundleRevision> ondemand)
+ {
+ m_state = state;
+ m_wirings = wirings;
+ m_mandatory = mandatory;
+ m_optional = optional;
+ m_ondemand = ondemand;
+ }
+
+ @Override
+ public Collection<BundleRevision> getMandatoryRevisions()
+ {
+ return new ArrayList<BundleRevision>(m_mandatory);
+ }
+
+ @Override
+ public Collection<BundleRevision> getOptionalRevisions()
+ {
+ return new ArrayList<BundleRevision>(m_optional);
+ }
+
+ public Collection<BundleRevision> getOndemandRevisions()
+ {
+ return new ArrayList<BundleRevision>(m_ondemand);
+ }
+
+ public List<BundleCapability> findProviders(BundleRequirement br, boolean obeyMandatory)
+ {
+ return m_state.findProviders(br, obeyMandatory);
+ }
+
+ public int insertHostedCapability(List<BundleCapability> caps, HostedCapability hc)
+ {
+ int idx = Collections.binarySearch(caps, hc, new CandidateComparator());
+ if (idx < 0)
+ {
+ idx = Math.abs(idx + 1);
+ }
+ caps.add(idx, hc);
+ return idx;
+ }
+
+ public boolean isEffective(BundleRequirement br)
+ {
+ return m_state.isEffective(br);
+ }
+
+ public Map<BundleRevision, BundleWiring> getWirings()
+ {
+ return m_wirings;
+ }
+
+ public void checkExecutionEnvironment(BundleRevision rev) throws ResolveException
+ {
+ m_state.checkExecutionEnvironment(rev);
+ }
+
+ 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/StatefulResolver.java b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index c099f15..376ffcb 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -28,9 +28,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.SortedSet;
import java.util.StringTokenizer;
-import java.util.TreeSet;
import org.apache.felix.framework.capabilityset.CapabilitySet;
import org.apache.felix.framework.capabilityset.SimpleFilter;
import org.apache.felix.framework.resolver.CandidateComparator;
@@ -64,33 +62,265 @@
private final Logger m_logger;
private final Felix m_felix;
private final Resolver m_resolver;
- private final ResolverStateImpl m_resolverState;
private final List<ResolverHook> m_hooks = new ArrayList<ResolverHook>();
private boolean m_isResolving = false;
private Collection<BundleRevision> m_whitelist = null;
+ // Set of all revisions.
+ private final Set<BundleRevision> m_revisions;
+ // Set of all fragments.
+ private final Set<BundleRevision> m_fragments;
+ // Capability sets.
+ private final Map<String, CapabilitySet> m_capSets;
+ // Maps singleton symbolic names to list of bundle revisions sorted by version.
+ private final Map<String, List<BundleRevision>> m_singletons;
+ // Selected singleton bundle revisions.
+ private final Set<BundleRevision> m_selectedSingletons;
+ // Execution environment.
+ private final String m_fwkExecEnvStr;
+ // Parsed framework environments
+ private final Set<String> m_fwkExecEnvSet;
+
StatefulResolver(Felix felix)
{
m_felix = felix;
m_logger = m_felix.getLogger();
m_resolver = new ResolverImpl(m_logger);
- m_resolverState = new ResolverStateImpl(
- (String) m_felix.getConfig().get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT));
+
+ m_revisions = new HashSet<BundleRevision>();
+ m_fragments = new HashSet<BundleRevision>();
+ m_capSets = new HashMap<String, CapabilitySet>();
+ m_singletons = new HashMap<String, List<BundleRevision>>();
+ m_selectedSingletons = new HashSet<BundleRevision>();
+
+ String fwkExecEnvStr =
+ (String) m_felix.getConfig().get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
+ m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
+ m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
+
+ List<String> indices = new ArrayList<String>();
+ indices.add(BundleRevision.BUNDLE_NAMESPACE);
+ m_capSets.put(BundleRevision.BUNDLE_NAMESPACE, new CapabilitySet(indices, true));
+
+ indices = new ArrayList<String>();
+ indices.add(BundleRevision.PACKAGE_NAMESPACE);
+ m_capSets.put(BundleRevision.PACKAGE_NAMESPACE, new CapabilitySet(indices, true));
+
+ indices = new ArrayList<String>();
+ indices.add(BundleRevision.HOST_NAMESPACE);
+ m_capSets.put(BundleRevision.HOST_NAMESPACE, new CapabilitySet(indices, true));
}
- void addRevision(BundleRevision br)
+ synchronized void addRevision(BundleRevision br)
{
- m_resolverState.addRevision(br);
+ // Always attempt to remove the revision, since
+ // this method can be used for re-indexing a revision
+ // after it has been resolved.
+ removeRevision(br);
+
+ m_revisions.add(br);
+
+ // Add singletons to the singleton map.
+ boolean isSingleton = Util.isSingleton(br);
+ if (isSingleton)
+ {
+ // Index the new singleton.
+ addToSingletonMap(m_singletons, br);
+ }
+
+ // We always need to index non-singleton bundle capabilities, but
+ // singleton bundles only need to be index if they are resolved.
+ // Unresolved singleton capabilities are only indexed before a
+ // resolve operation when singleton selection is performed.
+ if (!isSingleton || (br.getWiring() != null))
+ {
+ if (Util.isFragment(br))
+ {
+ m_fragments.add(br);
+ }
+ indexCapabilities(br);
+ }
}
- void removeRevision(BundleRevision br)
+ synchronized void removeRevision(BundleRevision br)
{
- m_resolverState.removeRevision(br);
+ if (m_revisions.remove(br))
+ {
+ m_fragments.remove(br);
+ deindexCapabilities(br);
+
+ // If this module is a singleton, then remove it from the
+ // singleton map.
+ List<BundleRevision> revisions = m_singletons.get(br.getSymbolicName());
+ if (revisions != null)
+ {
+ revisions.remove(br);
+ if (revisions.isEmpty())
+ {
+ m_singletons.remove(br.getSymbolicName());
+ }
+ }
+ }
}
- Set<BundleCapability> getCandidates(BundleRequirementImpl req, boolean obeyMandatory)
+ boolean isEffective(BundleRequirement req)
{
- return m_resolverState.getCandidates(req, obeyMandatory);
+ String effective = req.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
+ return ((effective == null) || effective.equals(Constants.EFFECTIVE_RESOLVE));
+ }
+
+ synchronized List<BundleCapability> findProviders(
+ BundleRequirement req, boolean obeyMandatory)
+ {
+ BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
+ List<BundleCapability> result = new ArrayList<BundleCapability>();
+
+ CapabilitySet capSet = m_capSets.get(req.getNamespace());
+ if (capSet != null)
+ {
+ // Get the requirement's filter; if this is our own impl we
+ // have a shortcut to get the already parsed filter, otherwise
+ // we must parse it from the directive.
+ SimpleFilter sf = null;
+ if (req instanceof BundleRequirementImpl)
+ {
+ sf = ((BundleRequirementImpl) req).getFilter();
+ }
+ else
+ {
+ String filter = req.getDirectives().get(Constants.FILTER_DIRECTIVE);
+ if (filter == null)
+ {
+ sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+ }
+ else
+ {
+ sf = SimpleFilter.parse(filter);
+ }
+ }
+
+ // Find the matching candidates.
+ Set<BundleCapability> matches = capSet.match(sf, obeyMandatory);
+ // Filter matching candidates.
+ for (BundleCapability cap : matches)
+ {
+ // Filter according to security.
+ if (filteredBySecurity(req, cap))
+ {
+ 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))
+ {
+ continue;
+ }
+
+ result.add(cap);
+ }
+ }
+
+ // If we have resolver hooks, then we may need to filter our results
+ // based on a whitelist and/or fine-grained candidate filtering.
+ if (!result.isEmpty() && !m_hooks.isEmpty())
+ {
+ // It we have a whitelist, then first filter out candidates
+ // from disallowed revisions.
+ if (m_whitelist != null)
+ {
+ for (Iterator<BundleCapability> it = result.iterator(); it.hasNext(); )
+ {
+ if (!m_whitelist.contains(it.next().getRevision()))
+ {
+ it.remove();
+ }
+ }
+ }
+
+ // Now give the hooks a chance to do fine-grained filtering.
+ ShrinkableCollection<BundleCapability> shrinkable =
+ new ShrinkableCollection<BundleCapability>(result);
+ for (ResolverHook hook : m_hooks)
+ {
+ try
+ {
+ Felix.m_secureAction
+ .invokeResolverHookMatches(hook, req, shrinkable);
+ }
+ catch (Throwable th)
+ {
+ m_logger.log(Logger.LOG_WARNING, "Resolver hook exception.", th);
+ }
+ }
+ }
+
+ Collections.sort(result, new CandidateComparator());
+
+ return result;
+ }
+
+ private boolean filteredBySecurity(BundleRequirement req, BundleCapability cap)
+ {
+ if (System.getSecurityManager() != null)
+ {
+ BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
+
+ if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
+ {
+ if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+ new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
+ PackagePermission.EXPORTONLY)) ||
+ !((reqRevision == null) ||
+ ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+ new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
+ cap.getRevision().getBundle(),PackagePermission.IMPORT))
+ ))
+ {
+ if (reqRevision != cap.getRevision())
+ {
+ return true;
+ }
+ }
+ }
+ else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
+ { if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+ new BundlePermission(cap.getRevision().getSymbolicName(), BundlePermission.PROVIDE)) ||
+ !((reqRevision == null) ||
+ ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+ new BundlePermission(reqRevision.getSymbolicName(), BundlePermission.REQUIRE))
+ ))
+ {
+ return true;
+ }
+ }
+ else if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
+ {
+ if (!((BundleProtectionDomain) reqRevision.getProtectionDomain())
+ .impliesDirect(new BundlePermission(
+ reqRevision.getSymbolicName(),
+ BundlePermission.FRAGMENT))
+ || !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain())
+ .impliesDirect(new BundlePermission(
+ cap.getRevision().getSymbolicName(),
+ BundlePermission.HOST)))
+ {
+ return true;
+ }
+ }
+ else if (!req.getNamespace().equals("osgi.ee"))
+ {
+ if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
+ new CapabilityPermission(req.getNamespace(), CapabilityPermission.PROVIDE))
+ ||
+ !((reqRevision == null) || ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
+ new CapabilityPermission(req.getNamespace(), cap.getAttributes(), cap.getRevision().getBundle(), CapabilityPermission.REQUIRE))))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
}
void resolve(
@@ -129,7 +359,7 @@
prepareResolverHooks(mandatory, optional);
// Select any singletons in the resolver state.
- m_resolverState.selectSingletons();
+ selectSingletons();
// Extensions are resolved differently.
for (Iterator<BundleRevision> it = mandatory.iterator(); it.hasNext(); )
@@ -140,7 +370,7 @@
{
it.remove();
}
- else if (Util.isSingleton(br) && !m_resolverState.isSelectedSingleton(br))
+ else if (Util.isSingleton(br) && !isSelectedSingleton(br))
{
throw new ResolveException("Singleton conflict.", br, null);
}
@@ -153,7 +383,7 @@
{
it.remove();
}
- else if (Util.isSingleton(br) && !m_resolverState.isSelectedSingleton(br))
+ else if (Util.isSingleton(br) && !isSelectedSingleton(br))
{
it.remove();
}
@@ -166,10 +396,12 @@
{
// Resolve the revision.
wireMap = m_resolver.resolve(
- m_resolverState,
- mandatory,
- optional,
- m_resolverState.getFragments());
+ new ResolveContextImpl(
+ this,
+ getWirings(),
+ mandatory,
+ optional,
+ getFragments()));
}
catch (ResolveException ex)
{
@@ -249,7 +481,7 @@
Collections.singleton(revision), Collections.EMPTY_SET);
// Select any singletons in the resolver state.
- m_resolverState.selectSingletons();
+ selectSingletons();
// Catch any resolve exception to rethrow later because
// we may need to call end() on resolver hooks.
@@ -257,8 +489,13 @@
try
{
wireMap = m_resolver.resolve(
- m_resolverState, revision, pkgName,
- m_resolverState.getFragments());
+ new ResolveContextImpl(
+ this,
+ getWirings(),
+ Collections.EMPTY_LIST,
+ Collections.EMPTY_LIST,
+ getFragments()),
+ revision, pkgName);
}
catch (ResolveException ex)
{
@@ -373,9 +610,7 @@
}
// Ask hooks to indicate which revisions should not be resolved.
- m_whitelist =
- new ShrinkableCollection<BundleRevision>(
- m_resolverState.getUnresolvedRevisions());
+ m_whitelist = new ShrinkableCollection<BundleRevision>(getUnresolvedRevisions());
int originalSize = m_whitelist.size();
for (ResolverHook hook : m_hooks)
{
@@ -518,7 +753,7 @@
BundleRevision.PACKAGE_NAMESPACE,
Collections.EMPTY_MAP,
attrs);
- Set<BundleCapability> candidates = m_resolverState.getCandidates(req, false);
+ List<BundleCapability> candidates = findProviders(req, false);
return !candidates.isEmpty();
}
@@ -713,7 +948,7 @@
// Reindex the revision's capabilities since its resolved
// capabilities could be different than its declared ones
// (e.g., due to substitutable exports).
- m_resolverState.addRevision(revision);
+ addRevision(revision);
// Update the state of the revision's bundle to resolved as well.
markBundleResolved(revision);
@@ -855,635 +1090,378 @@
return pkgs;
}
- class ResolverStateImpl implements Resolver.ResolverState
+ private synchronized void indexCapabilities(BundleRevision br)
{
- // Set of all revisions.
- private final Set<BundleRevision> m_revisions;
- // Set of all fragments.
- private final Set<BundleRevision> m_fragments;
- // Capability sets.
- private final Map<String, CapabilitySet> m_capSets;
- // Maps singleton symbolic names to list of bundle revisions sorted by version.
- private final Map<String, List<BundleRevision>> m_singletons;
- // Selected singleton bundle revisions.
- private final Set<BundleRevision> m_selectedSingletons;
- // Execution environment.
- private final String m_fwkExecEnvStr;
- // Parsed framework environments
- private final Set<String> m_fwkExecEnvSet;
-
-// void dump()
-// {
-// for (Entry<String, CapabilitySet> entry : m_capSets.entrySet())
-// {
-// System.out.println("+++ START CAPSET " + entry.getKey());
-// entry.getValue().dump();
-// System.out.println("+++ END CAPSET " + entry.getKey());
-// }
-// }
-
- ResolverStateImpl(String fwkExecEnvStr)
+ List<BundleCapability> caps =
+ (Util.isFragment(br) || (br.getWiring() == null))
+ ? br.getDeclaredCapabilities(null)
+ : br.getWiring().getCapabilities(null);
+ if (caps != null)
{
- m_revisions = new HashSet<BundleRevision>();
- m_fragments = new HashSet<BundleRevision>();
- m_capSets = new HashMap<String, CapabilitySet>();
- m_singletons = new HashMap<String, List<BundleRevision>>();
- m_selectedSingletons = new HashSet<BundleRevision>();
-
- m_fwkExecEnvStr = (fwkExecEnvStr != null) ? fwkExecEnvStr.trim() : null;
- m_fwkExecEnvSet = parseExecutionEnvironments(fwkExecEnvStr);
-
- List<String> indices = new ArrayList<String>();
- indices.add(BundleRevision.BUNDLE_NAMESPACE);
- m_capSets.put(BundleRevision.BUNDLE_NAMESPACE, new CapabilitySet(indices, true));
-
- indices = new ArrayList<String>();
- indices.add(BundleRevision.PACKAGE_NAMESPACE);
- m_capSets.put(BundleRevision.PACKAGE_NAMESPACE, new CapabilitySet(indices, true));
-
- indices = new ArrayList<String>();
- indices.add(BundleRevision.HOST_NAMESPACE);
- m_capSets.put(BundleRevision.HOST_NAMESPACE, new CapabilitySet(indices, true));
- }
-
- synchronized Set<BundleRevision> getUnresolvedRevisions()
- {
- Set<BundleRevision> unresolved = new HashSet<BundleRevision>();
- for (BundleRevision revision : m_revisions)
+ for (BundleCapability cap : caps)
{
- if (revision.getWiring() == null)
- {
- unresolved.add(revision);
- }
- }
- return unresolved;
- }
-
- synchronized void addRevision(BundleRevision br)
- {
- // Always attempt to remove the revision, since
- // this method can be used for re-indexing a revision
- // after it has been resolved.
- removeRevision(br);
-
- m_revisions.add(br);
-
- // Add singletons to the singleton map.
- boolean isSingleton = Util.isSingleton(br);
- if (isSingleton)
- {
- // Index the new singleton.
- addToSingletonMap(m_singletons, br);
- }
-
- // We always need to index non-singleton bundle capabilities, but
- // singleton bundles only need to be index if they are resolved.
- // Unresolved singleton capabilities are only indexed before a
- // resolve operation when singleton selection is performed.
- if (!isSingleton || (br.getWiring() != null))
- {
- if (Util.isFragment(br))
- {
- m_fragments.add(br);
- }
- indexCapabilities(br);
- }
- }
-
- private synchronized void indexCapabilities(BundleRevision br)
- {
- List<BundleCapability> caps =
- (Util.isFragment(br) || (br.getWiring() == null))
- ? br.getDeclaredCapabilities(null)
- : br.getWiring().getCapabilities(null);
- if (caps != null)
- {
- for (BundleCapability cap : caps)
- {
- // If the capability is from a different revision, then
- // don't index it since it is a capability from a fragment.
- // In that case, the fragment capability is still indexed.
- // It will be the resolver's responsibility to find all
- // attached hosts for fragments.
- if (cap.getRevision() == br)
- {
- CapabilitySet capSet = m_capSets.get(cap.getNamespace());
- if (capSet == null)
- {
- capSet = new CapabilitySet(null, true);
- m_capSets.put(cap.getNamespace(), capSet);
- }
- capSet.addCapability(cap);
- }
- }
- }
- }
-
- private synchronized void deindexCapabilities(BundleRevision br)
- {
- // We only need be concerned with declared capabilities here,
- // because resolved capabilities will be a subset, since fragment
- // capabilities are not considered to be part of the host.
- List<BundleCapability> caps = br.getDeclaredCapabilities(null);
- if (caps != null)
- {
- for (BundleCapability cap : caps)
+ // If the capability is from a different revision, then
+ // don't index it since it is a capability from a fragment.
+ // In that case, the fragment capability is still indexed.
+ // It will be the resolver's responsibility to find all
+ // attached hosts for fragments.
+ if (cap.getRevision() == br)
{
CapabilitySet capSet = m_capSets.get(cap.getNamespace());
- if (capSet != null)
+ if (capSet == null)
{
- capSet.removeCapability(cap);
+ capSet = new CapabilitySet(null, true);
+ m_capSets.put(cap.getNamespace(), capSet);
}
- }
- }
- }
-
- synchronized void removeRevision(BundleRevision br)
- {
- if (m_revisions.remove(br))
- {
- m_fragments.remove(br);
- deindexCapabilities(br);
-
- // If this module is a singleton, then remove it from the
- // singleton map.
- List<BundleRevision> revisions = m_singletons.get(br.getSymbolicName());
- if (revisions != null)
- {
- revisions.remove(br);
- if (revisions.isEmpty())
- {
- m_singletons.remove(br.getSymbolicName());
- }
- }
- }
- }
-
- synchronized Set<BundleRevision> getFragments()
- {
- Set<BundleRevision> fragments = new HashSet(m_fragments);
- // Filter out any fragments that are not the current revision.
- for (Iterator<BundleRevision> it = fragments.iterator(); it.hasNext(); )
- {
- BundleRevision fragment = it.next();
- BundleRevision currentFragmentRevision =
- fragment.getBundle().adapt(BundleRevision.class);
- if (fragment != currentFragmentRevision)
- {
- it.remove();
- }
- }
- return fragments;
- }
-
- synchronized boolean isSelectedSingleton(BundleRevision br)
- {
- return m_selectedSingletons.contains(br);
- }
-
- synchronized void selectSingletons()
- throws BundleException
- {
- // First deindex any unresolved singletons to make sure
- // there aren't any available from previous resolves.
- // Also remove them from the fragment list, for the same
- // reason.
- m_selectedSingletons.clear();
- for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
- {
- for (BundleRevision singleton : entry.getValue())
- {
- if (singleton.getWiring() == null)
- {
- deindexCapabilities(singleton);
- m_fragments.remove(singleton);
- }
- }
- }
-
- // If no resolver hooks, then use default singleton selection
- // algorithm, otherwise defer to the resolver hooks.
- if (m_hooks.isEmpty())
- {
- selectDefaultSingletons();
- }
- else
- {
- selectSingletonsUsingHooks();
- }
- }
-
- /*
- * Selects the singleton with the highest version from groupings
- * based on the symbolic name. No selection is made if the group
- * already has a resolved singleton.
- */
- private void selectDefaultSingletons()
- {
- // Now select the singletons available for this resolve operation.
- for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
- {
- selectSingleton(entry.getValue());
- }
- }
-
- /*
- * Groups singletons based on resolver hook filtering and then selects
- * the singleton from each group with the highest version that is in
- * the resolver hook whitelist. No selection is made if a group already
- * has a resolved singleton in it.
- */
- private void selectSingletonsUsingHooks()
- throws BundleException
- {
- // Convert singleton bundle revision map into a map using
- // bundle capabilities instead, since this is what the resolver
- // hooks require.
- Map<BundleCapability, Collection<BundleCapability>> allCollisions
- = new HashMap<BundleCapability, Collection<BundleCapability>>();
- for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
- {
- Collection<BundleCapability> bundleCaps =
- new ArrayList<BundleCapability>();
- for (BundleRevision br : entry.getValue())
- {
- List<BundleCapability> caps =
- br.getDeclaredCapabilities(BundleRevision.BUNDLE_NAMESPACE);
- if (!caps.isEmpty())
- {
- bundleCaps.add(caps.get(0));
- }
- }
-
- for (BundleCapability bc : bundleCaps)
- {
- Collection<BundleCapability> capCopy =
- new ShrinkableCollection<BundleCapability>(
- new ArrayList<BundleCapability>(bundleCaps));
- capCopy.remove(bc);
- allCollisions.put(bc, capCopy);
- }
- }
-
- // Invoke hooks to allow them to filter singleton collisions.
- for (ResolverHook hook : m_hooks)
- {
- for (Entry<BundleCapability, Collection<BundleCapability>> entry
- : allCollisions.entrySet())
- {
- try
- {
- Felix.m_secureAction
- .invokeResolverHookSingleton(hook, entry.getKey(), entry.getValue());
- }
- catch (Throwable ex)
- {
- throw new BundleException(
- "Resolver hook exception: " + ex.getMessage(),
- BundleException.REJECTED_BY_HOOK,
- ex);
- }
- }
- }
-
- // Create groups according to how the resolver hooks filtered the
- // collisions.
- List<List<BundleRevision>> groups = new ArrayList<List<BundleRevision>>();
- while (!allCollisions.isEmpty())
- {
- BundleCapability target = allCollisions.entrySet().iterator().next().getKey();
- groups.add(groupSingletons(allCollisions, target, new ArrayList<BundleRevision>()));
- }
-
- // Now select the singletons available for this resolve operation.
- for (List<BundleRevision> group : groups)
- {
- selectSingleton(group);
- }
- }
-
- private List<BundleRevision> groupSingletons(
- Map<BundleCapability, Collection<BundleCapability>> allCollisions,
- BundleCapability target, List<BundleRevision> group)
- {
- if (!group.contains(target.getRevision()))
- {
- // Add the target since it is implicitly part of the group.
- group.add(target.getRevision());
-
- // Recursively add the revisions of any singleton's in the
- // target's collisions.
- Collection<BundleCapability> collisions = allCollisions.remove(target);
- for (BundleCapability collision : collisions)
- {
- groupSingletons(allCollisions, collision, group);
- }
-
- // Need to check the values of other collisions for this target
- // and add those to the target's group too, since collisions are
- // treated as two-way relationships. Repeat until there are no
- // collision groups left that contain the target capability.
- boolean repeat;
- do
- {
- repeat = false;
- for (Entry<BundleCapability, Collection<BundleCapability>> entry:
- allCollisions.entrySet())
- {
- if (entry.getValue().contains(target))
- {
- repeat = true;
- groupSingletons(allCollisions, entry.getKey(), group);
- break;
- }
- }
- }
- while (repeat);
- }
- return group;
- }
-
- /*
- * Selects the highest bundle revision from the group that is
- * in the resolver hook whitelist (if there are hooks). No
- * selection is made if there is an already resolved singleton
- * in the group, since it is already indexed.
- */
- private void selectSingleton(List<BundleRevision> singletons)
- {
- BundleRevision selected = null;
- for (BundleRevision singleton : singletons)
- {
- // If a singleton is already resolved,
- // then there is nothing to do.
- if (singleton.getWiring() != null)
- {
- selected = null;
- break;
- }
- // If this singleton is not in the whitelist, then it cannot
- // be selected. If it is, in can only be selected if it has
- // a higher version than the currently selected singleton, if
- // there is one.
- if (((m_whitelist == null) || m_whitelist.contains(singleton))
- && ((selected == null)
- || (selected.getVersion().compareTo(singleton.getVersion()) > 0)))
- {
- selected = singleton;
- }
- }
- if (selected != null)
- {
- // Record the selected singleton.
- m_selectedSingletons.add(selected);
- // Index its capabilities.
- indexCapabilities(selected);
- // If the selected singleton is a fragment, then
- // add it to the list of fragments.
- if (Util.isFragment(selected))
- {
- m_fragments.add(selected);
- }
- }
- }
-
- //
- // ResolverState methods.
- //
-
- public boolean isEffective(BundleRequirement req)
- {
- String effective = req.getDirectives().get(Constants.EFFECTIVE_DIRECTIVE);
- return ((effective == null) || effective.equals(Constants.EFFECTIVE_RESOLVE));
- }
-
- public synchronized SortedSet<BundleCapability> getCandidates(
- BundleRequirement req, boolean obeyMandatory)
- {
- BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
- SortedSet<BundleCapability> result =
- new TreeSet<BundleCapability>(new CandidateComparator());
-
- CapabilitySet capSet = m_capSets.get(req.getNamespace());
- if (capSet != null)
- {
- // Get the requirement's filter; if this is our own impl we
- // have a shortcut to get the already parsed filter, otherwise
- // we must parse it from the directive.
- SimpleFilter sf = null;
- if (req instanceof BundleRequirementImpl)
- {
- sf = ((BundleRequirementImpl) req).getFilter();
- }
- else
- {
- String filter = req.getDirectives().get(Constants.FILTER_DIRECTIVE);
- if (filter == null)
- {
- sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
- }
- else
- {
- sf = SimpleFilter.parse(filter);
- }
- }
-
- // Find the matching candidates.
- Set<BundleCapability> matches = capSet.match(sf, obeyMandatory);
- // Filter matching candidates.
- for (BundleCapability cap : matches)
- {
- // Filter according to security.
- if (filteredBySecurity(req, cap))
- {
- 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))
- {
- continue;
- }
-
- result.add(cap);
- }
- }
-
- // If we have resolver hooks, then we may need to filter our results
- // based on a whitelist and/or fine-grained candidate filtering.
- if (!result.isEmpty() && !m_hooks.isEmpty())
- {
- // It we have a whitelist, then first filter out candidates
- // from disallowed revisions.
- if (m_whitelist != null)
- {
- for (Iterator<BundleCapability> it = result.iterator(); it.hasNext(); )
- {
- if (!m_whitelist.contains(it.next().getRevision()))
- {
- it.remove();
- }
- }
- }
-
- // Now give the hooks a chance to do fine-grained filtering.
- ShrinkableCollection<BundleCapability> shrinkable =
- new ShrinkableCollection<BundleCapability>(result);
- for (ResolverHook hook : m_hooks)
- {
- try
- {
- Felix.m_secureAction
- .invokeResolverHookMatches(hook, req, shrinkable);
- }
- catch (Throwable th)
- {
- m_logger.log(Logger.LOG_WARNING, "Resolver hook exception.", th);
- }
- }
- }
-
- return result;
- }
-
- private boolean filteredBySecurity(BundleRequirement req, BundleCapability cap)
- {
- if (System.getSecurityManager() != null)
- {
- BundleRevisionImpl reqRevision = (BundleRevisionImpl) req.getRevision();
-
- if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
- {
- if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
- new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
- PackagePermission.EXPORTONLY)) ||
- !((reqRevision == null) ||
- ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
- new PackagePermission((String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
- cap.getRevision().getBundle(),PackagePermission.IMPORT))
- ))
- {
- if (reqRevision != cap.getRevision())
- {
- return true;
- }
- }
- }
- else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
- { if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
- new BundlePermission(cap.getRevision().getSymbolicName(), BundlePermission.PROVIDE)) ||
- !((reqRevision == null) ||
- ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
- new BundlePermission(reqRevision.getSymbolicName(), BundlePermission.REQUIRE))
- ))
- {
- return true;
- }
- }
- else if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
- {
- if (!((BundleProtectionDomain) reqRevision.getProtectionDomain())
- .impliesDirect(new BundlePermission(
- reqRevision.getSymbolicName(),
- BundlePermission.FRAGMENT))
- || !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain())
- .impliesDirect(new BundlePermission(
- cap.getRevision().getSymbolicName(),
- BundlePermission.HOST)))
- {
- return true;
- }
- }
- else if (!req.getNamespace().equals("osgi.ee"))
- {
- if (!((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain()).impliesDirect(
- new CapabilityPermission(req.getNamespace(), CapabilityPermission.PROVIDE))
- ||
- !((reqRevision == null) || ((BundleProtectionDomain) reqRevision.getProtectionDomain()).impliesDirect(
- new CapabilityPermission(req.getNamespace(), cap.getAttributes(), cap.getRevision().getBundle(), CapabilityPermission.REQUIRE))))
- {
- return true;
- }
- }
- }
- return false;
- }
-
- public void checkExecutionEnvironment(BundleRevision revision) throws ResolveException
- {
- String bundleExecEnvStr = (String)
- ((BundleRevisionImpl) revision).getHeaders().get(
- Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
- if (bundleExecEnvStr != null)
- {
- bundleExecEnvStr = bundleExecEnvStr.trim();
-
- // If the bundle has specified an execution environment and the
- // framework has an execution environment specified, then we must
- // check for a match.
- if (!bundleExecEnvStr.equals("")
- && (m_fwkExecEnvStr != null)
- && (m_fwkExecEnvStr.length() > 0))
- {
- StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
- boolean found = false;
- while (tokens.hasMoreTokens() && !found)
- {
- if (m_fwkExecEnvSet.contains(tokens.nextToken().trim()))
- {
- found = true;
- }
- }
- if (!found)
- {
- throw new ResolveException(
- "Execution environment not supported: "
- + bundleExecEnvStr, revision, null);
- }
- }
- }
- }
-
- public void checkNativeLibraries(BundleRevision revision) throws ResolveException
- {
- // Next, try to resolve any native code, since the revision is
- // not resolvable if its native code cannot be loaded.
- List<R4Library> libs = ((BundleRevisionImpl) revision).getDeclaredNativeLibraries();
- if (libs != null)
- {
- String msg = null;
- // Verify that all native libraries exist in advance; this will
- // throw an exception if the native library does not exist.
- for (int libIdx = 0; (msg == null) && (libIdx < libs.size()); libIdx++)
- {
- String entryName = libs.get(libIdx).getEntryName();
- if (entryName != null)
- {
- if (!((BundleRevisionImpl) revision).getContent().hasEntry(entryName))
- {
- msg = "Native library does not exist: " + entryName;
- }
- }
- }
- // If we have a zero-length native library array, then
- // this means no native library class could be selected
- // so we should fail to resolve.
- if (libs.isEmpty())
- {
- msg = "No matching native libraries found.";
- }
- if (msg != null)
- {
- throw new ResolveException(msg, revision, null);
+ capSet.addCapability(cap);
}
}
}
}
- //
- // Utility methods.
- //
+ private synchronized void deindexCapabilities(BundleRevision br)
+ {
+ // We only need be concerned with declared capabilities here,
+ // because resolved capabilities will be a subset, since fragment
+ // capabilities are not considered to be part of the host.
+ List<BundleCapability> caps = br.getDeclaredCapabilities(null);
+ if (caps != null)
+ {
+ for (BundleCapability cap : caps)
+ {
+ CapabilitySet capSet = m_capSets.get(cap.getNamespace());
+ if (capSet != null)
+ {
+ capSet.removeCapability(cap);
+ }
+ }
+ }
+ }
+
+ private synchronized boolean isSelectedSingleton(BundleRevision br)
+ {
+ return m_selectedSingletons.contains(br);
+ }
+
+ private synchronized void selectSingletons()
+ throws BundleException
+ {
+ // First deindex any unresolved singletons to make sure
+ // there aren't any available from previous resolves.
+ // Also remove them from the fragment list, for the same
+ // reason.
+ m_selectedSingletons.clear();
+ for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
+ {
+ for (BundleRevision singleton : entry.getValue())
+ {
+ if (singleton.getWiring() == null)
+ {
+ deindexCapabilities(singleton);
+ m_fragments.remove(singleton);
+ }
+ }
+ }
+
+ // If no resolver hooks, then use default singleton selection
+ // algorithm, otherwise defer to the resolver hooks.
+ if (m_hooks.isEmpty())
+ {
+ selectDefaultSingletons();
+ }
+ else
+ {
+ selectSingletonsUsingHooks();
+ }
+ }
+
+ /*
+ * Selects the singleton with the highest version from groupings
+ * based on the symbolic name. No selection is made if the group
+ * already has a resolved singleton.
+ */
+ private void selectDefaultSingletons()
+ {
+ // Now select the singletons available for this resolve operation.
+ for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
+ {
+ selectSingleton(entry.getValue());
+ }
+ }
+
+ /*
+ * Groups singletons based on resolver hook filtering and then selects
+ * the singleton from each group with the highest version that is in
+ * the resolver hook whitelist. No selection is made if a group already
+ * has a resolved singleton in it.
+ */
+ private void selectSingletonsUsingHooks()
+ throws BundleException
+ {
+ // Convert singleton bundle revision map into a map using
+ // bundle capabilities instead, since this is what the resolver
+ // hooks require.
+ Map<BundleCapability, Collection<BundleCapability>> allCollisions
+ = new HashMap<BundleCapability, Collection<BundleCapability>>();
+ for (Entry<String, List<BundleRevision>> entry : m_singletons.entrySet())
+ {
+ Collection<BundleCapability> bundleCaps =
+ new ArrayList<BundleCapability>();
+ for (BundleRevision br : entry.getValue())
+ {
+ List<BundleCapability> caps =
+ br.getDeclaredCapabilities(BundleRevision.BUNDLE_NAMESPACE);
+ if (!caps.isEmpty())
+ {
+ bundleCaps.add(caps.get(0));
+ }
+ }
+
+ for (BundleCapability bc : bundleCaps)
+ {
+ Collection<BundleCapability> capCopy =
+ new ShrinkableCollection<BundleCapability>(
+ new ArrayList<BundleCapability>(bundleCaps));
+ capCopy.remove(bc);
+ allCollisions.put(bc, capCopy);
+ }
+ }
+
+ // Invoke hooks to allow them to filter singleton collisions.
+ for (ResolverHook hook : m_hooks)
+ {
+ for (Entry<BundleCapability, Collection<BundleCapability>> entry
+ : allCollisions.entrySet())
+ {
+ try
+ {
+ Felix.m_secureAction
+ .invokeResolverHookSingleton(hook, entry.getKey(), entry.getValue());
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
+ }
+
+ // Create groups according to how the resolver hooks filtered the
+ // collisions.
+ List<List<BundleRevision>> groups = new ArrayList<List<BundleRevision>>();
+ while (!allCollisions.isEmpty())
+ {
+ BundleCapability target = allCollisions.entrySet().iterator().next().getKey();
+ groups.add(groupSingletons(allCollisions, target, new ArrayList<BundleRevision>()));
+ }
+
+ // Now select the singletons available for this resolve operation.
+ for (List<BundleRevision> group : groups)
+ {
+ selectSingleton(group);
+ }
+ }
+
+ private List<BundleRevision> groupSingletons(
+ Map<BundleCapability, Collection<BundleCapability>> allCollisions,
+ BundleCapability target, List<BundleRevision> group)
+ {
+ if (!group.contains(target.getRevision()))
+ {
+ // Add the target since it is implicitly part of the group.
+ group.add(target.getRevision());
+
+ // Recursively add the revisions of any singleton's in the
+ // target's collisions.
+ Collection<BundleCapability> collisions = allCollisions.remove(target);
+ for (BundleCapability collision : collisions)
+ {
+ groupSingletons(allCollisions, collision, group);
+ }
+
+ // Need to check the values of other collisions for this target
+ // and add those to the target's group too, since collisions are
+ // treated as two-way relationships. Repeat until there are no
+ // collision groups left that contain the target capability.
+ boolean repeat;
+ do
+ {
+ repeat = false;
+ for (Entry<BundleCapability, Collection<BundleCapability>> entry:
+ allCollisions.entrySet())
+ {
+ if (entry.getValue().contains(target))
+ {
+ repeat = true;
+ groupSingletons(allCollisions, entry.getKey(), group);
+ break;
+ }
+ }
+ }
+ while (repeat);
+ }
+ return group;
+ }
+
+ /*
+ * Selects the highest bundle revision from the group that is
+ * in the resolver hook whitelist (if there are hooks). No
+ * selection is made if there is an already resolved singleton
+ * in the group, since it is already indexed.
+ */
+ private void selectSingleton(List<BundleRevision> singletons)
+ {
+ BundleRevision selected = null;
+ for (BundleRevision singleton : singletons)
+ {
+ // If a singleton is already resolved,
+ // then there is nothing to do.
+ if (singleton.getWiring() != null)
+ {
+ selected = null;
+ break;
+ }
+ // If this singleton is not in the whitelist, then it cannot
+ // be selected. If it is, in can only be selected if it has
+ // a higher version than the currently selected singleton, if
+ // there is one.
+ if (((m_whitelist == null) || m_whitelist.contains(singleton))
+ && ((selected == null)
+ || (selected.getVersion().compareTo(singleton.getVersion()) > 0)))
+ {
+ selected = singleton;
+ }
+ }
+ if (selected != null)
+ {
+ // Record the selected singleton.
+ m_selectedSingletons.add(selected);
+ // Index its capabilities.
+ indexCapabilities(selected);
+ // If the selected singleton is a fragment, then
+ // add it to the list of fragments.
+ if (Util.isFragment(selected))
+ {
+ m_fragments.add(selected);
+ }
+ }
+ }
+
+ private synchronized Set<BundleRevision> getFragments()
+ {
+ Set<BundleRevision> fragments = new HashSet(m_fragments);
+ // Filter out any fragments that are not the current revision.
+ for (Iterator<BundleRevision> it = fragments.iterator(); it.hasNext(); )
+ {
+ BundleRevision fragment = it.next();
+ BundleRevision currentFragmentRevision =
+ fragment.getBundle().adapt(BundleRevision.class);
+ if (fragment != currentFragmentRevision)
+ {
+ it.remove();
+ }
+ }
+ return fragments;
+ }
+
+ void checkExecutionEnvironment(BundleRevision revision) throws ResolveException
+ {
+ String bundleExecEnvStr = (String)
+ ((BundleRevisionImpl) revision).getHeaders().get(
+ Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
+ if (bundleExecEnvStr != null)
+ {
+ bundleExecEnvStr = bundleExecEnvStr.trim();
+
+ // If the bundle has specified an execution environment and the
+ // framework has an execution environment specified, then we must
+ // check for a match.
+ if (!bundleExecEnvStr.equals("")
+ && (m_fwkExecEnvStr != null)
+ && (m_fwkExecEnvStr.length() > 0))
+ {
+ StringTokenizer tokens = new StringTokenizer(bundleExecEnvStr, ",");
+ boolean found = false;
+ while (tokens.hasMoreTokens() && !found)
+ {
+ if (m_fwkExecEnvSet.contains(tokens.nextToken().trim()))
+ {
+ found = true;
+ }
+ }
+ if (!found)
+ {
+ throw new ResolveException(
+ "Execution environment not supported: "
+ + bundleExecEnvStr, revision, null);
+ }
+ }
+ }
+ }
+
+ void checkNativeLibraries(BundleRevision revision) throws ResolveException
+ {
+ // Next, try to resolve any native code, since the revision is
+ // not resolvable if its native code cannot be loaded.
+ List<R4Library> libs = ((BundleRevisionImpl) revision).getDeclaredNativeLibraries();
+ if (libs != null)
+ {
+ String msg = null;
+ // Verify that all native libraries exist in advance; this will
+ // throw an exception if the native library does not exist.
+ for (int libIdx = 0; (msg == null) && (libIdx < libs.size()); libIdx++)
+ {
+ String entryName = libs.get(libIdx).getEntryName();
+ if (entryName != null)
+ {
+ if (!((BundleRevisionImpl) revision).getContent().hasEntry(entryName))
+ {
+ msg = "Native library does not exist: " + entryName;
+ }
+ }
+ }
+ // If we have a zero-length native library array, then
+ // this means no native library class could be selected
+ // so we should fail to resolve.
+ if (libs.isEmpty())
+ {
+ msg = "No matching native libraries found.";
+ }
+ if (msg != null)
+ {
+ throw new ResolveException(msg, revision, null);
+ }
+ }
+ }
+
+ private synchronized Set<BundleRevision> getUnresolvedRevisions()
+ {
+ Set<BundleRevision> unresolved = new HashSet<BundleRevision>();
+ for (BundleRevision revision : m_revisions)
+ {
+ if (revision.getWiring() == null)
+ {
+ unresolved.add(revision);
+ }
+ }
+ return unresolved;
+ }
+
+ private synchronized Map<BundleRevision, BundleWiring> getWirings()
+ {
+ Map<BundleRevision, BundleWiring> wirings = new HashMap<BundleRevision, BundleWiring>();
+
+ for (BundleRevision revision : m_revisions)
+ {
+ if (revision.getWiring() != null)
+ {
+ wirings.put(revision, revision.getWiring());
+ }
+ }
+ return wirings;
+ }
/**
* Updates the framework wide execution environment string and a cached Set of
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
index d244685..1d8722a 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
@@ -27,11 +27,8 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.SortedSet;
import java.util.TreeMap;
-import java.util.TreeSet;
-import org.apache.felix.framework.BundleRevisionImpl;
-import org.apache.felix.framework.resolver.Resolver.ResolverState;
+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;
@@ -50,15 +47,14 @@
public static final int OPTIONAL = 1;
public static final int ON_DEMAND = 2;
- // Set of all mandatory bundle revisions.
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, SortedSet<BundleCapability>> m_candidateMap;
+ 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, HostBundleRevision> m_allWrappedHosts;
+ 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;
@@ -75,8 +71,8 @@
private Candidates(
Set<BundleRevision> mandatoryRevisions,
Map<BundleCapability, Set<BundleRequirement>> dependentMap,
- Map<BundleRequirement, SortedSet<BundleCapability>> candidateMap,
- Map<BundleRevision, HostBundleRevision> wrappedHosts, Map<BundleRevision, Object> populateResultCache,
+ Map<BundleRequirement, List<BundleCapability>> candidateMap,
+ Map<BundleRevision, WrappedRevision> wrappedHosts, Map<BundleRevision, Object> populateResultCache,
boolean fragmentsPresent)
{
m_mandatoryRevisions = mandatoryRevisions;
@@ -94,8 +90,8 @@
{
m_mandatoryRevisions = new HashSet<BundleRevision>();
m_dependentMap = new HashMap<BundleCapability, Set<BundleRequirement>>();
- m_candidateMap = new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
- m_allWrappedHosts = new HashMap<BundleRevision, HostBundleRevision>();
+ m_candidateMap = new HashMap<BundleRequirement, List<BundleCapability>>();
+ m_allWrappedHosts = new HashMap<BundleRevision, WrappedRevision>();
m_populateResultCache = new HashMap<BundleRevision, Object>();
}
@@ -116,7 +112,7 @@
* @param resolution indicates the resolution type.
*/
public final void populate(
- ResolverState state, BundleRevision revision, int resolution)
+ ResolveContext rc, BundleRevision revision, int resolution)
{
// Get the current result cache value, to make sure the revision
// hasn't already been populated.
@@ -146,7 +142,7 @@
// However, for on-demand fragments only populate if their host
// is already populated.
if ((resolution != ON_DEMAND)
- || (isFragment && populateFragmentOndemand(state, revision)))
+ || (isFragment && populateFragmentOndemand(rc, revision)))
{
if (resolution == MANDATORY)
{
@@ -155,7 +151,7 @@
try
{
// Try to populate candidates for the optional revision.
- populateRevision(state, revision);
+ populateRevision(rc, revision);
}
catch (ResolveException ex)
{
@@ -174,7 +170,7 @@
* @param revision the revision whose candidates should be populated.
*/
// TODO: FELIX3 - Modify to not be recursive.
- private void populateRevision(ResolverState state, BundleRevision revision)
+ 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:
@@ -196,7 +192,7 @@
// Keeps track of the candidates we've already calculated for the
// current revision's requirements.
- Map<BundleRequirement, SortedSet<BundleCapability>> localCandidateMap = null;
+ Map<BundleRequirement, List<BundleCapability>> localCandidateMap = null;
// Keeps track of the current revision's requirements for which we
// haven't yet found candidates.
@@ -234,10 +230,10 @@
if ((remainingReqs == null) && (localCandidateMap == null))
{
// Verify that any required execution environment is satisfied.
- state.checkExecutionEnvironment(revision);
+ ((ResolveContextImpl) rc).checkExecutionEnvironment(revision);
// Verify that any native libraries match the current platform.
- state.checkNativeLibraries(revision);
+ ((ResolveContextImpl) rc).checkNativeLibraries(revision);
// Record cycle count.
cycleCount = new Integer(0);
@@ -263,7 +259,7 @@
// Ignore non-effective and dynamic requirements.
String resolution = req.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
- if (!state.isEffective(req)
+ if (!rc.isEffective(req)
|| ((resolution != null)
&& resolution.equals(FelixConstants.RESOLUTION_DYNAMIC)))
{
@@ -272,9 +268,8 @@
// Process the candidates, removing any candidates that
// cannot resolve.
- SortedSet<BundleCapability> candidates =
- state.getCandidates((BundleRequirementImpl) req, true);
- ResolveException rethrow = processCandidates(state, revision, candidates);
+ 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.
@@ -324,7 +319,7 @@
}
}
- private boolean populateFragmentOndemand(ResolverState state, BundleRevision revision)
+ private boolean populateFragmentOndemand(ResolveContext rc, BundleRevision revision)
throws ResolveException
{
// Create a modifiable list of the revision's requirements.
@@ -344,8 +339,7 @@
}
}
// Get candidates hosts and keep any that have been populated.
- SortedSet<BundleCapability> hosts =
- state.getCandidates((BundleRequirementImpl) hostReq, false);
+ List<BundleCapability> hosts = rc.findProviders(hostReq, false);
for (Iterator<BundleCapability> it = hosts.iterator(); it.hasNext(); )
{
BundleCapability host = it.next();
@@ -364,16 +358,16 @@
// some other checks and prepopulate the result cache with
// the work we've done so far.
// Verify that any required execution environment is satisfied.
- state.checkExecutionEnvironment(revision);
+ ((ResolveContextImpl) rc).checkExecutionEnvironment(revision);
// Verify that any native libraries match the current platform.
- state.checkNativeLibraries(revision);
+ ((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, SortedSet<BundleCapability>> localCandidateMap =
- new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
+ 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
@@ -385,8 +379,8 @@
}
public void populateDynamic(
- ResolverState state, BundleRevision revision,
- BundleRequirement req, SortedSet<BundleCapability> candidates)
+ ResolveContext rc, BundleRevision revision,
+ BundleRequirement req, List<BundleCapability> candidates)
{
// Record the revision associated with the dynamic require
// as a mandatory revision.
@@ -397,7 +391,7 @@
// Process the candidates, removing any candidates that
// cannot resolve.
- ResolveException rethrow = processCandidates(state, revision, candidates);
+ ResolveException rethrow = processCandidates(rc, revision, candidates);
if (candidates.isEmpty())
{
@@ -423,9 +417,9 @@
* @return a resolve exception to be re-thrown, if any, or null.
*/
private ResolveException processCandidates(
- ResolverState state,
+ ResolveContext rc,
BundleRevision revision,
- SortedSet<BundleCapability> candidates)
+ List<BundleCapability> candidates)
{
// Get satisfying candidates and populate their candidates if necessary.
ResolveException rethrow = null;
@@ -466,7 +460,7 @@
{
try
{
- populateRevision(state, candCap.getRevision());
+ populateRevision(rc, candCap.getRevision());
}
catch (ResolveException ex)
{
@@ -505,8 +499,19 @@
{
// Note that we can just add this as a candidate
// directly, since we know it is already resolved.
- candidates.add(
- new HostedCapability(
+ // 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));
}
@@ -540,7 +545,7 @@
* @param req the requirement to add.
* @param candidates the candidates matching the requirement.
**/
- private void add(BundleRequirement req, SortedSet<BundleCapability> candidates)
+ private void add(BundleRequirement req, List<BundleCapability> candidates)
{
if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
{
@@ -557,9 +562,9 @@
* be further modified by the caller.
* @param candidates the bulk requirements and candidates to add.
**/
- private void add(Map<BundleRequirement, SortedSet<BundleCapability>> candidates)
+ private void add(Map<BundleRequirement, List<BundleCapability>> candidates)
{
- for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry : candidates.entrySet())
+ for (Entry<BundleRequirement, List<BundleCapability>> entry : candidates.entrySet())
{
add(entry.getKey(), entry.getValue());
}
@@ -583,7 +588,7 @@
* @param req the requirement whose candidates are desired.
* @return the matching candidates or null.
**/
- public SortedSet<BundleCapability> getCandidates(BundleRequirement req)
+ public List<BundleCapability> getCandidates(BundleRequirement req)
{
return m_candidateMap.get(req);
}
@@ -604,7 +609,7 @@
* @throws ResolveException if the removal of any unselected fragments result
* in the root module being unable to resolve.
**/
- public void prepare()
+ 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
@@ -632,7 +637,7 @@
// with host's attached fragment capabilities.
// Steps 1 and 2
- List<HostBundleRevision> hostRevisions = new ArrayList<HostBundleRevision>();
+ List<WrappedRevision> hostRevisions = new ArrayList<WrappedRevision>();
List<BundleRevision> unselectedFragments = new ArrayList<BundleRevision>();
for (Entry<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
hostEntry : hostFragments.entrySet())
@@ -667,7 +672,7 @@
else
{
m_dependentMap.get(hostCap).remove(hostReq);
- SortedSet<BundleCapability> hosts = m_candidateMap.get(hostReq);
+ List<BundleCapability> hosts = m_candidateMap.get(hostReq);
hosts.remove(hostCap);
if (hosts.isEmpty())
{
@@ -679,8 +684,8 @@
}
// Step 2
- HostBundleRevision wrappedHost =
- new HostBundleRevision(hostCap.getRevision(), selectedFragments);
+ WrappedRevision wrappedHost =
+ new WrappedRevision(hostCap.getRevision(), selectedFragments);
hostRevisions.add(wrappedHost);
m_allWrappedHosts.put(hostCap.getRevision(), wrappedHost);
}
@@ -694,7 +699,7 @@
}
// Step 4
- for (HostBundleRevision hostRevision : hostRevisions)
+ for (WrappedRevision hostRevision : hostRevisions)
{
// Replaces capabilities from fragments with the capabilities
// from the merged host.
@@ -704,8 +709,7 @@
// really be attached to the original host, not the wrapper.
if (!c.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
{
- BundleCapability origCap =
- ((HostedCapability) c).getOriginalCapability();
+ 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
@@ -717,9 +721,63 @@
m_dependentMap.put(c, dependents);
for (BundleRequirement r : dependents)
{
- Set<BundleCapability> cands = m_candidateMap.get(r);
- cands.remove(origCap);
- cands.add(c);
+ // 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);
+ }
}
}
}
@@ -729,11 +787,11 @@
for (BundleRequirement r : hostRevision.getDeclaredRequirements(null))
{
BundleRequirement origReq =
- ((HostedRequirement) r).getOriginalRequirement();
- SortedSet<BundleCapability> cands = m_candidateMap.get(origReq);
+ ((WrappedRequirement) r).getOriginalRequirement();
+ List<BundleCapability> cands = m_candidateMap.get(origReq);
if (cands != null)
{
- m_candidateMap.put(r, new TreeSet<BundleCapability>(cands));
+ m_candidateMap.put(r, new ArrayList<BundleCapability>(cands));
for (BundleCapability cand : cands)
{
Set<BundleRequirement> dependents = m_dependentMap.get(cand);
@@ -766,11 +824,10 @@
Map<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
hostFragments = new HashMap<BundleCapability,
Map<String, Map<Version, List<BundleRequirement>>>>();
- for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry
- : m_candidateMap.entrySet())
+ for (Entry<BundleRequirement, List<BundleCapability>> entry : m_candidateMap.entrySet())
{
BundleRequirement req = entry.getKey();
- SortedSet<BundleCapability> caps = entry.getValue();
+ List<BundleCapability> caps = entry.getValue();
for (BundleCapability cap : caps)
{
// Record the requirement as dependent on the capability.
@@ -871,7 +928,7 @@
{
boolean isFragment = req.getNamespace().equals(BundleRevision.HOST_NAMESPACE);
- SortedSet<BundleCapability> candidates = m_candidateMap.remove(req);
+ List<BundleCapability> candidates = m_candidateMap.remove(req);
if (candidates != null)
{
for (BundleCapability cap : candidates)
@@ -902,7 +959,7 @@
{
for (BundleRequirement r : dependents)
{
- SortedSet<BundleCapability> candidates = m_candidateMap.get(r);
+ List<BundleCapability> candidates = m_candidateMap.get(r);
candidates.remove(c);
if (candidates.isEmpty())
{
@@ -935,13 +992,13 @@
dependentMap.put(entry.getKey(), dependents);
}
- Map<BundleRequirement, SortedSet<BundleCapability>> candidateMap =
- new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
- for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry
+ Map<BundleRequirement, List<BundleCapability>> candidateMap =
+ new HashMap<BundleRequirement, List<BundleCapability>>();
+ for (Entry<BundleRequirement, List<BundleCapability>> entry
: m_candidateMap.entrySet())
{
- SortedSet<BundleCapability> candidates =
- new TreeSet<BundleCapability>(entry.getValue());
+ List<BundleCapability> candidates =
+ new ArrayList<BundleCapability>(entry.getValue());
candidateMap.put(entry.getKey(), candidates);
}
@@ -954,7 +1011,7 @@
{
// Create set of all revisions from requirements.
Set<BundleRevision> revisions = new HashSet<BundleRevision>();
- for (Entry<BundleRequirement, SortedSet<BundleCapability>> entry
+ for (Entry<BundleRequirement, List<BundleCapability>> entry
: m_candidateMap.entrySet())
{
revisions.add(entry.getKey().getRevision());
@@ -970,7 +1027,7 @@
: br.getDeclaredRequirements(null);
for (BundleRequirement req : reqs)
{
- Set<BundleCapability> candidates = m_candidateMap.get(req);
+ List<BundleCapability> candidates = m_candidateMap.get(req);
if ((candidates != null) && (candidates.size() > 0))
{
System.out.println(" " + req + ": " + candidates);
@@ -981,7 +1038,7 @@
: Util.getDynamicRequirements(br.getDeclaredRequirements(null));
for (BundleRequirement req : reqs)
{
- Set<BundleCapability> candidates = m_candidateMap.get(req);
+ List<BundleCapability> candidates = m_candidateMap.get(req);
if ((candidates != null) && (candidates.size() > 0))
{
System.out.println(" " + req + ": " + candidates);
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
index dbdad1c..fc45301 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
@@ -1,122 +1,26 @@
/*
- * 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
+ * Copyright (c) OSGi Alliance (2012). All Rights Reserved.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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
*
- * 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.
+ * 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;
-public class HostedCapability extends BundleCapabilityImpl
-{
- private final BundleRevision m_host;
- private final BundleCapabilityImpl m_cap;
+public interface HostedCapability extends BundleCapability {
- public HostedCapability(BundleRevision host, BundleCapabilityImpl cap)
- {
- super(host, cap.getNamespace(), cap.getDirectives(), cap.getAttributes());
- m_host = host;
- m_cap = cap;
- }
+ BundleRevision getRevision();
- @Override
- public boolean equals(Object obj)
- {
- if (obj == null)
- {
- return false;
- }
- if (getClass() != obj.getClass())
- {
- return false;
- }
- final HostedCapability other = (HostedCapability) 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 BundleCapabilityImpl getOriginalCapability()
- {
- return m_cap;
- }
-
- @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
+ 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
new file mode 100644
index 0000000..2af0696
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolveContext.java
@@ -0,0 +1,52 @@
+/*
+ * 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/Resolver.java b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
index eabfdd1..107e4a7 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
@@ -28,21 +28,7 @@
public interface Resolver
{
+ Map<BundleRevision, List<ResolverWire>> resolve(ResolveContext rc);
Map<BundleRevision, List<ResolverWire>> resolve(
- ResolverState state,
- Set<BundleRevision> mandatoryRevisions,
- Set<BundleRevision> optionalRevisions,
- Set<BundleRevision> ondemandFragments);
- Map<BundleRevision, List<ResolverWire>> resolve(
- ResolverState state, BundleRevision revision, String pkgName,
- Set<BundleRevision> ondemandFragments);
-
- public static interface ResolverState
- {
- boolean isEffective(BundleRequirement req);
- SortedSet<BundleCapability> getCandidates(
- BundleRequirement req, boolean obeyMandatory);
- void checkExecutionEnvironment(BundleRevision revision) throws ResolveException;
- void checkNativeLibraries(BundleRevision revision) throws ResolveException;
- }
+ 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
index 56203b3..8f1fabc 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
@@ -19,6 +19,7 @@
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;
@@ -30,6 +31,7 @@
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;
@@ -57,17 +59,17 @@
m_logger = logger;
}
- public Map<BundleRevision, List<ResolverWire>> resolve(
- ResolverState state,
- Set<BundleRevision> mandatoryRevisions,
- Set<BundleRevision> optionalRevisions,
- Set<BundleRevision> ondemandFragments)
+ 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
{
@@ -86,7 +88,7 @@
BundleRevision br = it.next();
if (Util.isFragment(br) || (br.getWiring() == null))
{
- allCandidates.populate(state, br, Candidates.MANDATORY);
+ allCandidates.populate(rc, br, Candidates.MANDATORY);
}
else
{
@@ -101,7 +103,7 @@
boolean isFragment = Util.isFragment(br);
if (isFragment || (br.getWiring() == null))
{
- allCandidates.populate(state, br, Candidates.OPTIONAL);
+ allCandidates.populate(rc, br, Candidates.OPTIONAL);
}
}
@@ -112,12 +114,12 @@
boolean isFragment = Util.isFragment(br);
if (isFragment)
{
- allCandidates.populate(state, br, Candidates.ON_DEMAND);
+ allCandidates.populate(rc, br, Candidates.ON_DEMAND);
}
}
// Merge any fragments into hosts.
- allCandidates.prepare();
+ allCandidates.prepare(rc);
// Create a combined list of populated revisions; for
// optional revisions. We do not need to consider ondemand
@@ -207,11 +209,11 @@
if (rethrow != null)
{
BundleRevision faultyRevision =
- getActualBundleRevision(rethrow.getRevision());
- if (rethrow.getRequirement() instanceof HostedRequirement)
+ getDeclaringBundleRevision(rethrow.getRevision());
+ if (rethrow.getRequirement() instanceof WrappedRequirement)
{
faultyRevision =
- ((HostedRequirement) rethrow.getRequirement())
+ ((WrappedRequirement) rethrow.getRequirement())
.getOriginalRequirement().getRevision();
}
if (optionalRevisions.remove(faultyRevision))
@@ -267,8 +269,7 @@
}
public Map<BundleRevision, List<ResolverWire>> resolve(
- ResolverState state, BundleRevision revision, String pkgName,
- Set<BundleRevision> ondemandFragments)
+ ResolveContext rc, BundleRevision revision, String pkgName)
{
// We can only create a dynamic import if the following
// conditions are met:
@@ -280,11 +281,16 @@
// The following call checks all of these conditions and returns
// the associated dynamic import and matching capabilities.
Candidates allCandidates =
- getDynamicImportCandidates(state, revision, pkgName);
+ getDynamicImportCandidates(rc, revision, pkgName);
if (allCandidates != null)
{
- Map<BundleRevision, List<ResolverWire>> wireMap = new HashMap<BundleRevision, List<ResolverWire>>();
- Map<BundleRevision, Packages> revisionPkgMap = new HashMap<BundleRevision, Packages>();
+ 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
@@ -298,12 +304,12 @@
{
if (Util.isFragment(br))
{
- allCandidates.populate(state, br, Candidates.ON_DEMAND);
+ allCandidates.populate(rc, br, Candidates.ON_DEMAND);
}
}
// Merge any fragments into hosts.
- allCandidates.prepare();
+ allCandidates.prepare(rc);
// Record the initial candidate permutation.
m_usesPermutations.add(allCandidates);
@@ -355,11 +361,11 @@
if (rethrow != null)
{
BundleRevision faultyRevision =
- getActualBundleRevision(rethrow.getRevision());
- if (rethrow.getRequirement() instanceof HostedRequirement)
+ getDeclaringBundleRevision(rethrow.getRevision());
+ if (rethrow.getRequirement() instanceof WrappedRequirement)
{
faultyRevision =
- ((HostedRequirement) rethrow.getRequirement())
+ ((WrappedRequirement) rethrow.getRequirement())
.getOriginalRequirement().getRevision();
}
if (ondemandFragments.remove(faultyRevision))
@@ -394,7 +400,7 @@
}
private static Candidates getDynamicImportCandidates(
- ResolverState state, BundleRevision revision, String pkgName)
+ ResolveContext rc, BundleRevision revision, String pkgName)
{
// Unresolved revisions cannot dynamically import, nor can the default
// package be dynamically imported.
@@ -438,7 +444,7 @@
BundleRevision.PACKAGE_NAMESPACE,
Collections.EMPTY_MAP,
attrs);
- SortedSet<BundleCapability> candidates = state.getCandidates(req, false);
+ List<BundleCapability> candidates = rc.findProviders(req, false);
// Try to find a dynamic requirement that matches the capabilities.
BundleRequirementImpl dynReq = null;
@@ -484,7 +490,7 @@
if (candidates.size() > 0)
{
allCandidates = new Candidates();
- allCandidates.populateDynamic(state, revision, dynReq, candidates);
+ allCandidates.populateDynamic(rc, revision, dynReq, candidates);
}
return allCandidates;
@@ -523,7 +529,7 @@
|| ((r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE) != null)
&& r.getDirectives().get(Constants.RESOLUTION_DIRECTIVE).equals("dynamic")))
{
- r = new HostedRequirement(
+ r = new WrappedRequirement(
wire.getRequirerWiring().getRevision(),
(BundleRequirementImpl) r);
}
@@ -532,7 +538,7 @@
BundleCapability c = wire.getCapability();
if (!c.getRevision().equals(wire.getProviderWiring().getRevision()))
{
- c = new HostedCapability(
+ c = new WrappedCapability(
wire.getProviderWiring().getRevision(),
(BundleCapabilityImpl) c);
}
@@ -547,15 +553,15 @@
: Util.getDynamicRequirements(revision.getWiring().getRequirements(null)))
{
// Get the candidates for the current requirement.
- SortedSet<BundleCapability> candCaps =
- allCandidates.getCandidates((BundleRequirementImpl) req);
+ List<BundleCapability> candCaps = allCandidates.getCandidates(req);
// Optional requirements may not have any candidates.
if (candCaps == null)
{
continue;
}
- BundleCapability cap = candCaps.iterator().next();
+ // Grab first (i.e., highest priority) candidate.
+ BundleCapability cap = candCaps.get(0);
reqs.add(req);
caps.add(cap);
isDynamicImporting = true;
@@ -573,15 +579,15 @@
|| !resolution.equals(FelixConstants.RESOLUTION_DYNAMIC))
{
// Get the candidates for the current requirement.
- SortedSet<BundleCapability> candCaps =
- allCandidates.getCandidates((BundleRequirementImpl) req);
+ List<BundleCapability> candCaps = allCandidates.getCandidates(req);
// Optional requirements may not have any candidates.
if (candCaps == null)
{
continue;
}
- BundleCapability cap = candCaps.iterator().next();
+ // Grab first (i.e., highest priority) candidate.
+ BundleCapability cap = candCaps.get(0);
reqs.add(req);
caps.add(cap);
}
@@ -974,6 +980,7 @@
}
}
+ // Check if there are any uses conflicts with exported packages.
for (Entry<String, Blame> entry : pkgs.m_exportedPkgs.entrySet())
{
String pkgName = entry.getKey();
@@ -1026,14 +1033,12 @@
// 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.
- SortedSet<BundleCapability> candidates =
- permutation.getCandidates(req);
+ List<BundleCapability> candidates = permutation.getCandidates(req);
if ((candidates != null) && (candidates.size() > 1))
{
mutated.add(req);
- Iterator it = candidates.iterator();
- it.next();
- it.remove();
+ // Remove the conflicting candidate.
+ candidates.remove(0);
// Continue with the next uses constraint.
break;
}
@@ -1115,14 +1120,12 @@
// 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.
- SortedSet<BundleCapability> candidates =
- permutation.getCandidates(req);
+ List<BundleCapability> candidates = permutation.getCandidates(req);
if ((candidates != null) && (candidates.size() > 1))
{
mutated.add(req);
- Iterator it = candidates.iterator();
- it.next();
- it.remove();
+ // Remove the conflicting candidate.
+ candidates.remove(0);
// Continue with the next uses constraint.
break;
}
@@ -1207,14 +1210,12 @@
private static void permutate(
Candidates allCandidates, BundleRequirement req, List<Candidates> permutations)
{
- SortedSet<BundleCapability> candidates = allCandidates.getCandidates(req);
+ List<BundleCapability> candidates = allCandidates.getCandidates(req);
if (candidates.size() > 1)
{
Candidates perm = allCandidates.copy();
candidates = perm.getCandidates(req);
- Iterator it = candidates.iterator();
- it.next();
- it.remove();
+ candidates.remove(0);
permutations.add(perm);
}
}
@@ -1222,7 +1223,7 @@
private static void permutateIfNeeded(
Candidates allCandidates, BundleRequirement req, List<Candidates> permutations)
{
- SortedSet<BundleCapability> candidates = allCandidates.getCandidates(req);
+ List<BundleCapability> candidates = allCandidates.getCandidates(req);
if (candidates.size() > 1)
{
// Check existing permutations to make sure we haven't
@@ -1234,8 +1235,8 @@
boolean permutated = false;
for (Candidates existingPerm : permutations)
{
- Set<BundleCapability> existingPermCands = existingPerm.getCandidates(req);
- if (!existingPermCands.iterator().next().equals(candidates.iterator().next()))
+ List<BundleCapability> existingPermCands = existingPerm.getCandidates(req);
+ if (!existingPermCands.get(0).equals(candidates.get(0)))
{
permutated = true;
}
@@ -1273,7 +1274,7 @@
{
if (!cap.getRevision().equals(revision))
{
- cap = new HostedCapability(revision, (BundleCapabilityImpl) cap);
+ cap = new WrappedCapability(revision, (BundleCapabilityImpl) cap);
}
exports.put(
(String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
@@ -1293,11 +1294,10 @@
{
if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
{
- Set<BundleCapability> cands =
- allCandidates.getCandidates((BundleRequirementImpl) req);
+ List<BundleCapability> cands = allCandidates.getCandidates(req);
if ((cands != null) && !cands.isEmpty())
{
- String pkgName = (String) cands.iterator().next()
+ String pkgName = (String) cands.get(0)
.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
exports.remove(pkgName);
}
@@ -1401,7 +1401,7 @@
if (!cap.getRevision().equals(sourceCap.getRevision()))
{
sources.add(
- new HostedCapability(cap.getRevision(), (BundleCapabilityImpl) sourceCap));
+ new WrappedCapability(cap.getRevision(), (BundleCapabilityImpl) sourceCap));
}
else
{
@@ -1425,29 +1425,29 @@
return sources;
}
- private static BundleRevision getActualBundleRevision(BundleRevision br)
+ private static BundleRevision getDeclaringBundleRevision(BundleRevision br)
{
- if (br instanceof HostBundleRevision)
+ if (br instanceof WrappedRevision)
{
- return ((HostBundleRevision) br).getHost();
+ return ((WrappedRevision) br).getHost();
}
return br;
}
- private static BundleCapability getActualCapability(BundleCapability c)
+ private static BundleCapability getDeclaredCapability(BundleCapability c)
{
if (c instanceof HostedCapability)
{
- return ((HostedCapability) c).getOriginalCapability();
+ return ((HostedCapability) c).getDeclaredCapability();
}
return c;
}
- private static BundleRequirement getActualRequirement(BundleRequirement r)
+ private static BundleRequirement getDeclaredRequirement(BundleRequirement r)
{
- if (r instanceof HostedRequirement)
+ if (r instanceof WrappedRequirement)
{
- return ((HostedRequirement) r).getOriginalRequirement();
+ return ((WrappedRequirement) r).getOriginalRequirement();
}
return r;
}
@@ -1457,7 +1457,7 @@
Map<BundleRevision, List<ResolverWire>> wireMap,
Candidates allCandidates)
{
- BundleRevision unwrappedRevision = getActualBundleRevision(revision);
+ BundleRevision unwrappedRevision = getDeclaringBundleRevision(revision);
if ((unwrappedRevision.getWiring() == null)
&& !wireMap.containsKey(unwrappedRevision))
{
@@ -1469,10 +1469,10 @@
for (BundleRequirement req : revision.getDeclaredRequirements(null))
{
- SortedSet<BundleCapability> cands = allCandidates.getCandidates(req);
+ List<BundleCapability> cands = allCandidates.getCandidates(req);
if ((cands != null) && (cands.size() > 0))
{
- BundleCapability cand = cands.iterator().next();
+ BundleCapability cand = cands.get(0);
// Ignore revisions that import themselves.
if (!revision.equals(cand.getRevision()))
{
@@ -1484,9 +1484,9 @@
Packages candPkgs = revisionPkgMap.get(cand.getRevision());
ResolverWire wire = new ResolverWireImpl(
unwrappedRevision,
- getActualRequirement(req),
- getActualBundleRevision(cand.getRevision()),
- getActualCapability(cand));
+ getDeclaredRequirement(req),
+ getDeclaringBundleRevision(cand.getRevision()),
+ getDeclaredCapability(cand));
if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
{
packageWires.add(wire);
@@ -1509,9 +1509,9 @@
wireMap.put(unwrappedRevision, packageWires);
// Add host wire for any fragments.
- if (revision instanceof HostBundleRevision)
+ if (revision instanceof WrappedRevision)
{
- List<BundleRevision> fragments = ((HostBundleRevision) revision).getFragments();
+ List<BundleRevision> fragments = ((WrappedRevision) revision).getFragments();
for (BundleRevision fragment : fragments)
{
List<ResolverWire> hostWires = wireMap.get(fragment);
@@ -1522,7 +1522,7 @@
}
hostWires.add(
new ResolverWireImpl(
- getActualBundleRevision(fragment),
+ getDeclaringBundleRevision(fragment),
fragment.getDeclaredRequirements(
BundleRevision.HOST_NAMESPACE).get(0),
unwrappedRevision,
@@ -1549,8 +1549,7 @@
: Util.getDynamicRequirements(revision.getWiring().getRequirements(null)))
{
// Get the candidates for the current dynamic requirement.
- SortedSet<BundleCapability> candCaps =
- allCandidates.getCandidates((BundleRequirementImpl) req);
+ List<BundleCapability> candCaps = allCandidates.getCandidates(req);
// Optional requirements may not have any candidates.
if ((candCaps == null) || candCaps.isEmpty())
{
@@ -1559,7 +1558,7 @@
// Record the dynamic requirement.
dynReq = req;
- dynCand = candCaps.first();
+ dynCand = candCaps.get(0);
// Can only dynamically import one at a time, so break
// out of the loop after the first.
@@ -1580,8 +1579,8 @@
new ResolverWireImpl(
revision,
dynReq,
- getActualBundleRevision(dynCand.getRevision()),
- getActualCapability(dynCand)));
+ getDeclaringBundleRevision(dynCand.getRevision()),
+ getDeclaredCapability(dynCand)));
}
wireMap.put(revision, packageWires);
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
new file mode 100644
index 0000000..e64b559
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/ShadowList.java
@@ -0,0 +1,157 @@
+/*
+ * 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
new file mode 100644
index 0000000..5e31d03
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/SimpleHostedCapability.java
@@ -0,0 +1,60 @@
+/*
+ * 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 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
new file mode 100644
index 0000000..7a21ec4
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedCapability.java
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+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 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/HostedRequirement.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
similarity index 93%
rename from framework/src/main/java/org/apache/felix/framework/resolver/HostedRequirement.java
rename to framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
index 58dadce..c0d15e0 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostedRequirement.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRequirement.java
@@ -23,12 +23,12 @@
import org.apache.felix.framework.wiring.BundleRequirementImpl;
import org.osgi.framework.wiring.BundleRevision;
-public class HostedRequirement extends BundleRequirementImpl
+public class WrappedRequirement extends BundleRequirementImpl
{
private final BundleRevision m_host;
private final BundleRequirementImpl m_req;
- public HostedRequirement(BundleRevision host, BundleRequirementImpl req)
+ public WrappedRequirement(BundleRevision host, BundleRequirementImpl req)
{
super(host, req.getNamespace(), req.getDirectives(), req.getAttributes());
m_host = host;
@@ -46,7 +46,7 @@
{
return false;
}
- final HostedRequirement other = (HostedRequirement) obj;
+ final WrappedRequirement other = (WrappedRequirement) obj;
if (m_host != other.m_host && (m_host == null || !m_host.equals(other.m_host)))
{
return false;
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
similarity index 89%
rename from framework/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java
rename to framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
index 3f052bb..81c41ee 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/HostBundleRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
@@ -30,14 +30,14 @@
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleWiring;
-class HostBundleRevision implements BundleRevision
+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 HostBundleRevision(BundleRevision host, List<BundleRevision> fragments)
+ public WrappedRevision(BundleRevision host, List<BundleRevision> fragments)
{
m_host = host;
m_fragments = fragments;
@@ -72,7 +72,7 @@
// Wrap host capabilities.
for (BundleCapability cap : m_host.getDeclaredCapabilities(null))
{
- caps.add(new HostedCapability(this, (BundleCapabilityImpl) cap));
+ caps.add(new WrappedCapability(this, (BundleCapabilityImpl) cap));
}
// Wrap fragment capabilities.
@@ -84,7 +84,7 @@
{
// 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 HostedCapability(this, (BundleCapabilityImpl) cap));
+ caps.add(new WrappedCapability(this, (BundleCapabilityImpl) cap));
}
}
}
@@ -102,7 +102,7 @@
// Wrap host requirements.
for (BundleRequirement req : m_host.getDeclaredRequirements(null))
{
- reqs.add(new HostedRequirement(this, (BundleRequirementImpl) req));
+ reqs.add(new WrappedRequirement(this, (BundleRequirementImpl) req));
}
// Wrap fragment requirements.
@@ -114,7 +114,7 @@
{
if (!req.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
{
- reqs.add(new HostedRequirement(this, (BundleRequirementImpl) req));
+ reqs.add(new WrappedRequirement(this, (BundleRequirementImpl) req));
}
}
}