You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2011/06/15 20:57:20 UTC
svn commit: r1136150 [1/2] - in
/felix/trunk/framework/src/main/java/org/apache/felix/framework: ./
resolver/ util/ util/manifestparser/ wiring/
Author: rickhall
Date: Wed Jun 15 18:57:20 2011
New Revision: 1136150
URL: http://svn.apache.org/viewvc?rev=1136150&view=rev
Log:
Implement most of the functionality for resolver hooks (FELIX-2986) along
with some other changes for R4.3 API (FELIX-2950).
Removed:
felix/trunk/framework/src/main/java/org/apache/felix/framework/ResolverStateImpl.java
Modified:
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ShrinkableCollection.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
felix/trunk/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java Wed Jun 15 18:57:20 2011
@@ -162,17 +162,22 @@ class BundleImpl implements Bundle
}
else
{
- // Dispose of the current revisions.
+ // Get current revision, since we can reuse it.
+ BundleRevisionImpl current = (BundleRevisionImpl) adapt(BundleRevision.class);
+ // Close all existing revisions.
closeRevisions();
+ // Clear all revisions.
+ m_revisions.clear();
- // Now we will purge all old revisions, only keeping the newest one.
+ // Purge all old archive revisions, only keeping the newest one.
m_archive.purge();
- // Lastly, we want to reset our bundle be reinitializing our state
- // and recreating a revision object for the newest revision.
- m_revisions.clear();
- final BundleRevision br = createRevision();
- addRevision(br);
+ // Reset the content of the current bundle revision.
+ current.resetContent(m_archive.getCurrentRevision().getContent());
+ // Re-add the revision to the bundle.
+ addRevision(current);
+
+ // Reset the bundle state.
m_state = Bundle.INSTALLED;
m_stale = false;
m_cachedHeaders.clear();
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionDependencies.java Wed Jun 15 18:57:20 2011
@@ -157,7 +157,7 @@ class BundleRevisionDependencies
// Get exported package name.
String pkgName = (String)
- exportCap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+ exportCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
// Get all importers and requirers for all revisions of the bundle.
// The spec says that require-bundle should be returned with importers.
@@ -171,7 +171,7 @@ class BundleRevisionDependencies
{
BundleCapability cap = entry.getKey();
if ((cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
- && cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)
+ && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
.equals(pkgName))
|| cap.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
{
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java Wed Jun 15 18:57:20 2011
@@ -51,7 +51,6 @@ public class BundleRevisionImpl implemen
private final Logger m_logger;
private final Map m_configMap;
private final String m_id;
- private final Content m_content;
private final Map m_headerMap;
private final URLStreamHandler m_streamHandler;
@@ -69,6 +68,7 @@ public class BundleRevisionImpl implemen
private final Bundle m_bundle;
+ private Content m_content;
private List<Content> m_contentPath;
private ProtectionDomain m_protectionDomain = null;
private final static SecureAction m_secureAction = new SecureAction();
@@ -362,11 +362,16 @@ public class BundleRevisionImpl implemen
// Content access methods.
//
- public Content getContent()
+ public synchronized Content getContent()
{
return m_content;
}
+ synchronized void resetContent(Content content)
+ {
+ m_content = content;
+ }
+
synchronized List<Content> getContentPath()
{
if (m_contentPath == null)
@@ -607,7 +612,7 @@ public class BundleRevisionImpl implemen
}
if (index == 0)
{
- return m_content.hasEntry(urlPath);
+ return getContent().hasEntry(urlPath);
}
return getContentPath().get(index - 1).hasEntry(urlPath);
}
@@ -621,7 +626,7 @@ public class BundleRevisionImpl implemen
}
if (index == 0)
{
- return m_content.getEntryAsStream(urlPath);
+ return getContent().getEntryAsStream(urlPath);
}
return getContentPath().get(index - 1).getEntryAsStream(urlPath);
}
@@ -634,7 +639,7 @@ public class BundleRevisionImpl implemen
}
if (index == 0)
{
- return m_content.getEntryAsURL(urlPath);
+ return getContent().getEntryAsURL(urlPath);
}
return getContentPath().get(index - 1).getEntryAsURL(urlPath);
}
@@ -676,6 +681,7 @@ public class BundleRevisionImpl implemen
m_logger.log(Logger.LOG_ERROR, "Error releasing revision: " + ex.getMessage(), ex);
}
m_content.close();
+ m_content = null;
for (int i = 0; (m_contentPath != null) && (i < m_contentPath.size()); i++)
{
m_contentPath.get(i).close();
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java Wed Jun 15 18:57:20 2011
@@ -403,7 +403,7 @@ public class BundleWiringImpl implements
{
m_wires.add(wire);
m_importedPkgs.put(
- (String) wire.getCapability().getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR),
+ (String) wire.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
wire.getProviderWiring().getRevision());
}
@@ -537,7 +537,7 @@ public class BundleWiringImpl implements
{
m_resolver.resolve(m_revision);
}
- catch (ResolveException ex)
+ catch (Exception ex)
{
// The spec states that if the bundle cannot be resolved, then
// only the local bundle's resources should be searched. So we
@@ -639,6 +639,10 @@ public class BundleWiringImpl implements
{
// Ignore this since it is likely normal.
}
+ catch (BundleException ex)
+ {
+ // Ignore this since it is likely the result of a resolver hook.
+ }
if (provider != null)
{
// Delegate to the provider revision.
@@ -886,20 +890,11 @@ public class BundleWiringImpl implements
}
}
}
- catch (ResolveException ex)
+// TODO: OSGi R4.3 - If we eliminate resolving from this method, then we can
+// simplify this catch, since resolve throws resolve and bundle exceptions.
+ catch (Exception ex)
{
- if (isClass)
- {
- // We do not use the resolve exception as the
- // cause of the exception, since this would
- // potentially leak internal module information.
- throw new ClassNotFoundException(
- name + " not found because "
- + getBundle()
- + " cannot resolve: "
- + ex.getRequirement());
- }
- else
+ if (!isClass && (ex instanceof ResolveException))
{
// The spec states that if the bundle cannot be resolved, then
// only the local bundle's resources should be searched. So we
@@ -909,13 +904,38 @@ public class BundleWiringImpl implements
{
return url;
}
+ }
- // We need to throw a resource not found exception.
- throw new ResourceNotFoundException(
- name + " not found because "
- + getBundle()
- + " cannot resolve: "
- + ex.getRequirement());
+ if (isClass)
+ {
+ if (!(ex instanceof ClassNotFoundException))
+ {
+ ClassNotFoundException cnfe = new ClassNotFoundException(
+ name
+ + " not found in "
+ + getBundle()
+ + " : "
+ + ex.getMessage());
+ex.printStackTrace();
+ cnfe.initCause(ex);
+ throw cnfe;
+ }
+ throw (ClassNotFoundException) ex;
+ }
+ else
+ {
+ if (!(ex instanceof ResourceNotFoundException))
+ {
+ ResourceNotFoundException rnfe = new ResourceNotFoundException(
+ name
+ + " not found in "
+ + getBundle()
+ + " : "
+ + ex.getMessage());
+ rnfe.initCause(ex);
+ throw rnfe;
+ }
+ throw (ResourceNotFoundException) ex;
}
}
finally
@@ -965,10 +985,14 @@ public class BundleWiringImpl implements
return result;
}
- // If no class was found, then we must throw an exception
+ // If no class or resource was found, then we must throw an exception
// since the provider of this package did not contain the
// requested class and imported packages are atomic.
- throw new ClassNotFoundException(name);
+ if (isClass)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ throw new ResourceNotFoundException(name);
}
// Check if the package is required.
@@ -1017,6 +1041,10 @@ public class BundleWiringImpl implements
{
// Ignore this since it is likely normal.
}
+ catch (BundleException ex)
+ {
+ // Ignore this since it is likely the result of a resolver hook.
+ }
// If the dynamic import was successful, then this initial
// time we must directly return the result from dynamically
@@ -1858,7 +1886,7 @@ public class BundleWiringImpl implements
for (int i = 0; (wires != null) && (i < wires.size()); i++)
{
if (wires.get(i).getCapability().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) &&
- wires.get(i).getCapability().getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).equals(pkgName))
+ wires.get(i).getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
{
String exporter = wires.get(i).getProviderWiring().getBundle().toString();
@@ -1949,7 +1977,7 @@ public class BundleWiringImpl implements
// Try to see if there is an exporter available.
Map<String, String> dirs = Collections.EMPTY_MAP;
Map<String, Object> attrs = new HashMap<String, Object>(1);
- attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+ attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(
revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
Set<BundleCapability> exporters = resolver.getCandidates(req, false);
@@ -1988,7 +2016,7 @@ public class BundleWiringImpl implements
// Next, check to see if there are any exporters for the package at all.
Map<String, String> dirs = Collections.EMPTY_MAP;
Map<String, Object> attrs = new HashMap<String, Object>(1);
- attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+ attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(
revision, BundleRevision.PACKAGE_NAMESPACE, dirs, attrs);
Set<BundleCapability> exports = resolver.getCandidates(req, false);
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java Wed Jun 15 18:57:20 2011
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -42,7 +42,7 @@ class ExportedPackageImpl implements Exp
m_exportingBundle = exporter;
m_exportingRevision = revision;
m_export = export;
- m_pkgName = (String) m_export.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+ m_pkgName = (String) m_export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
m_version = (!m_export.getAttributes().containsKey(BundleCapabilityImpl.VERSION_ATTR))
? Version.emptyVersion
: (Version) m_export.getAttributes().get(BundleCapabilityImpl.VERSION_ATTR);
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java Wed Jun 15 18:57:20 2011
@@ -447,7 +447,7 @@ class ExtensionManager extends URLStream
// Append exported package information.
exportSB.append(m_capabilities.get(i)
- .getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+ .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
for (Entry<String, String> entry
: m_capabilities.get(i).getDirectives().entrySet())
{
@@ -460,7 +460,7 @@ class ExtensionManager extends URLStream
for (Entry<String, Object> entry
: m_capabilities.get(i).getAttributes().entrySet())
{
- if (!entry.getKey().equals(BundleCapabilityImpl.PACKAGE_ATTR)
+ if (!entry.getKey().equals(BundleRevision.PACKAGE_NAMESPACE)
&& !entry.getKey().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
&& !entry.getKey().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
{
@@ -474,7 +474,7 @@ class ExtensionManager extends URLStream
// Remember exported packages.
exportNames.add(m_capabilities.get(i)
- .getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+ .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
}
}
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Wed Jun 15 18:57:20 2011
@@ -1531,11 +1531,23 @@ public class Felix extends BundleImpl im
{
return null;
}
-// TODO: OSGi R4.3 - Currently, we try to resolve resource requests in
+// TODO: OSGi R4.3 - Previously, we try to resolve resource requests in
// findClassOrResourceByDelegation() and fall back to local resource
-// searching if it fails. Perhaps we should attempt the resolve here
-// and do the local searching here. This means we could get rid of
-// resolve attempts in findClassOrResourceByDelegation().
+// searching if it fails. Now we must attempt the resolve here since
+// we cannot search by delegation until we are resolved and do the local
+// searching here if we fail. This means we could get rid of resolve
+// attempts in findClassOrResourceByDelegation().
+ try
+ {
+ resolveBundleRevision(bundle.adapt(BundleRevision.class));
+ }
+ catch (Exception ex)
+ {
+ // Ignore.
+ }
+
+ // If the bundle revision isn't resolved, then just search
+ // locally, otherwise delegate.
if (bundle.adapt(BundleRevision.class).getWiring() == null)
{
return ((BundleRevisionImpl) bundle.adapt(BundleRevision.class))
@@ -1561,11 +1573,21 @@ public class Felix extends BundleImpl im
{
return null;
}
-// TODO: OSGi R4.3 - Currently, we try to resolve resource requests in
-// findResourcesByDelegation() and fall back to local resource
-// searching if it fails. Perhaps we should attempt the resolve here
-// and do the local searching here. This means we could get rid of
-// resolve attempts in findResourcesByDelegation().
+// TODO: OSGi R4.3 - Previously, we try to resolve resource requests in
+// findClassOrResourceByDelegation() and fall back to local resource
+// searching if it fails. Now we must attempt the resolve here since
+// we cannot search by delegation until we are resolved and do the local
+// searching here if we fail. This means we could get rid of resolve
+// attempts in findClassOrResourceByDelegation().
+ try
+ {
+ resolveBundleRevision(bundle.adapt(BundleRevision.class));
+ }
+ catch (Exception ex)
+ {
+ // Ignore.
+ }
+
if (bundle.adapt(BundleRevision.class).getWiring() == null)
{
return ((BundleRevisionImpl) bundle.adapt(BundleRevision.class))
@@ -1726,7 +1748,7 @@ public class Felix extends BundleImpl im
{
try
{
- resolveBundle(bundle);
+ resolveBundleRevision(bundle.adapt(BundleRevision.class));
}
catch (BundleException ex)
{
@@ -1881,7 +1903,7 @@ public class Felix extends BundleImpl im
case Bundle.ACTIVE:
return;
case Bundle.INSTALLED:
- resolveBundle(bundle);
+ resolveBundleRevision(bundle.adapt(BundleRevision.class));
// No break.
case Bundle.RESOLVED:
// Set the bundle's context.
@@ -2037,7 +2059,9 @@ public class Felix extends BundleImpl im
}
// Rethrow all other exceptions as a BundleException.
- throw new BundleException("Activator start error in bundle " + bundle + ".", th);
+ throw new BundleException(
+ "Activator start error in bundle " + bundle + ".",
+ BundleException.ACTIVATOR_ERROR, th);
}
}
finally
@@ -3427,7 +3451,7 @@ public class Felix extends BundleImpl im
{
// First, get all exporters of the package.
Map<String, Object> attrs = new HashMap<String, Object>(1);
- attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+ attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(
null,
BundleRevision.PACKAGE_NAMESPACE,
@@ -3580,9 +3604,9 @@ public class Felix extends BundleImpl im
// BundleWiring.getCapabilities() returns the proper result. We probably
// Won't even need this method.
String pkgName = (String)
- cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+ cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
Map<String, Object> attrs = new HashMap<String, Object>(1);
- attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+ attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
BundleRequirementImpl req =
new BundleRequirementImpl(
null,
@@ -3637,22 +3661,15 @@ public class Felix extends BundleImpl im
try
{
+ // Remember original targets.
+ Collection<Bundle> originalTargets = targets;
+
// Determine set of bundles to be resolved, which is either the
// specified bundles or all bundles if null.
if (targets == null)
{
- targets = new ArrayList<Bundle>();
-
- // Add all unresolved bundles to the list.
- Iterator iter = m_installedBundles[LOCATION_MAP_IDX].values().iterator();
- while (iter.hasNext())
- {
- BundleImpl bundle = (BundleImpl) iter.next();
- if (bundle.getState() == Bundle.INSTALLED)
- {
- targets.add(bundle);
- }
- }
+ // Add all bundles to the list.
+ targets = m_installedBundles[LOCATION_MAP_IDX].values();
}
// Now resolve each target bundle.
@@ -3661,17 +3678,45 @@ public class Felix extends BundleImpl im
// If there are targets, then resolve each one.
if (!targets.isEmpty())
{
+ // Get bundle revisions for bundles in INSTALLED state.
+ Set<BundleRevision> revisions =
+ new HashSet<BundleRevision>(targets.size());
for (Bundle b : targets)
{
- try
+ if (b.getState() != Bundle.UNINSTALLED)
{
- resolveBundle((BundleImpl) b);
+ revisions.add(b.adapt(BundleRevision.class));
}
- catch (BundleException ex)
+ }
+ // If we had to filter any of the original targets, then
+ // the return result will be false regardless.
+ if ((originalTargets != null) && (originalTargets.size() != revisions.size()))
+ {
+ result = false;
+ }
+ try
+ {
+ m_resolver.resolve(revisions);
+ if (result)
{
- result = false;
+ for (BundleRevision br : revisions)
+ {
+ if (br.getWiring() == null)
+ {
+ result = false;
+ break;
+ }
+ }
}
}
+ catch (ResolveException ex)
+ {
+ result = false;
+ }
+ catch (BundleException ex)
+ {
+ result = false;
+ }
}
return result;
@@ -3683,11 +3728,11 @@ public class Felix extends BundleImpl im
}
}
- private void resolveBundle(Bundle bundle) throws BundleException
+ private void resolveBundleRevision(BundleRevision revision) throws BundleException
{
try
{
- m_resolver.resolve(bundle.adapt(BundleRevision.class));
+ m_resolver.resolve(revision);
}
catch (ResolveException ex)
{
@@ -3696,11 +3741,11 @@ public class Felix extends BundleImpl im
Bundle b = ex.getRevision().getBundle();
throw new BundleException(
"Unresolved constraint in bundle "
- + b + ": " + ex.getMessage());
+ + b + ": " + ex.getMessage(), BundleException.RESOLVE_ERROR);
}
else
{
- throw new BundleException(ex.getMessage());
+ throw new BundleException(ex.getMessage(), BundleException.RESOLVE_ERROR);
}
}
}
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java Wed Jun 15 18:57:20 2011
@@ -19,6 +19,7 @@
package org.apache.felix.framework;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -27,17 +28,30 @@ import java.util.List;
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.resolver.CandidateComparator;
import org.apache.felix.framework.resolver.ResolveException;
import org.apache.felix.framework.resolver.Resolver;
import org.apache.felix.framework.resolver.ResolverImpl;
import org.apache.felix.framework.resolver.ResolverWire;
+import org.apache.felix.framework.util.ShrinkableCollection;
import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.R4Library;
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.apache.felix.framework.wiring.BundleRequirementImpl;
import org.apache.felix.framework.wiring.BundleWireImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundlePermission;
import org.osgi.framework.Constants;
+import org.osgi.framework.PackagePermission;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.resolver.ResolverHook;
+import org.osgi.framework.hooks.resolver.ResolverHookFactory;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
@@ -48,6 +62,9 @@ class StatefulResolver
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;
StatefulResolver(Felix felix)
{
@@ -72,15 +89,13 @@ class StatefulResolver
return m_resolverState.getCandidates(req, obeyMandatory);
}
- void resolve(BundleRevision rootRevision) throws ResolveException
+ void resolve(BundleRevision rootRevision) throws ResolveException, BundleException
{
// Although there is a race condition to check the bundle state
// then lock it, we do this because we don't want to acquire the
// a lock just to check if the revision is resolved, which itself
// is a safe read. If the revision isn't resolved, we end up double
// check the resolved status later.
-// TODO: OSGi R4.3 - This locking strategy here depends on how we ultimately
-// implement getWiring(), which may change.
if (rootRevision.getWiring() == null)
{
// Acquire global lock.
@@ -91,26 +106,151 @@ class StatefulResolver
"Unable to acquire global lock for resolve.", rootRevision, null);
}
+ // Make sure we are not already resolving, which can be
+ // the case if a resolver hook does something bad.
+ if (m_isResolving)
+ {
+ m_felix.releaseGlobalLock();
+ throw new IllegalStateException("Nested resolve operations not allowed.");
+ }
+ m_isResolving = true;
+
Map<BundleRevision, List<ResolverWire>> wireMap = null;
try
{
- BundleImpl bundle = (BundleImpl) rootRevision.getBundle();
-
// Extensions are resolved differently.
+ BundleImpl bundle = (BundleImpl) rootRevision.getBundle();
if (bundle.isExtension())
{
return;
}
- // Resolve the revision.
- wireMap = m_resolver.resolve(
- m_resolverState, rootRevision, m_resolverState.getFragments());
+ // Get resolver hook factories.
+ Set<ServiceReference<ResolverHookFactory>> hookRefs =
+ m_felix.getHooks(ResolverHookFactory.class);
+ if (!hookRefs.isEmpty())
+ {
+ // Create triggers list.
+ List<BundleRevision> triggers = new ArrayList<BundleRevision>(1);
+ triggers.add(rootRevision);
+ triggers = Collections.unmodifiableList(triggers);
+
+ // Create resolver hook objects by calling begin() on factory.
+ for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+ {
+ try
+ {
+ ResolverHook hook = m_felix.getService(m_felix, ref).begin(triggers);
+ if (hook != null)
+ {
+ m_hooks.add(hook);
+ }
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
- // Mark all revisions as resolved.
+ // Ask hooks to indicate which revisions should not be resolved.
+ m_whitelist =
+ new ShrinkableCollection<BundleRevision>(
+ m_resolverState.getUnresolvedRevisions());
+ int originalSize = m_whitelist.size();
+ for (ResolverHook hook : m_hooks)
+ {
+ try
+ {
+ hook.filterResolvable(m_whitelist);
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
+ // If nothing was removed, then just null the whitelist
+ // as an optimization.
+ if (m_whitelist.size() == originalSize)
+ {
+ m_whitelist = null;
+ }
+
+ // Check to make sure the target revision is allowed to resolve.
+ if ((m_whitelist != null) && !m_whitelist.contains(rootRevision))
+ {
+ throw new ResolveException(
+ "Resolver hook prevented resolution.", rootRevision, null);
+ }
+ }
+
+ // Catch any resolve exception to rethrow later because
+ // we may need to call end() on resolver hooks.
+ ResolveException rethrow = null;
+ try
+ {
+ // Resolve the revision.
+ wireMap = m_resolver.resolve(
+ m_resolverState, rootRevision, m_resolverState.getFragments());
+ }
+ catch (ResolveException ex)
+ {
+ rethrow = ex;
+ }
+
+ // If we have resolver hooks, we must call end() on them.
+ if (!hookRefs.isEmpty())
+ {
+ // Verify that all resolver hook service references are still valid
+ // Call end() on resolver hooks.
+ for (ResolverHook hook : m_hooks)
+ {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+// to their svc ref since we aren't supposed to call end() on unregistered
+// but currently we call end() on all.
+ hook.end();
+ }
+ // Verify that all hook service references are still valid
+ // and unget all resolver hook factories.
+ boolean invalid = false;
+ for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+ {
+ if (ref.getBundle() == null)
+ {
+ invalid = true;
+ }
+ m_felix.ungetService(m_felix, ref);
+ }
+ if (invalid)
+ {
+ throw new BundleException(
+ "Resolver hook service unregistered during resolve.",
+ BundleException.REJECTED_BY_HOOK);
+ }
+ }
+
+ // If the resolve failed, rethrow the exception.
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+
+ // Otherwise, mark all revisions as resolved.
markResolvedRevisions(wireMap);
}
finally
{
+ // Clear resolving flag.
+ m_isResolving = false;
+ // Clear whitelist.
+ m_whitelist = null;
+ // Always clear any hooks.
+ m_hooks.clear();
// Always release the global lock.
m_felix.releaseGlobalLock();
}
@@ -119,8 +259,186 @@ class StatefulResolver
}
}
+// TODO: OSGi R4.3 - Isn't this method just a generalization of the above method?
+// Can't we combine them and perhaps simplify the various resolve() methods
+// here and in Felix.java too?
+ void resolve(Set<BundleRevision> revisions) throws ResolveException, BundleException
+ {
+ // Acquire global lock.
+ boolean locked = m_felix.acquireGlobalLock();
+ if (!locked)
+ {
+ throw new ResolveException(
+ "Unable to acquire global lock for resolve.", null, null);
+ }
+
+ // Make sure we are not already resolving, which can be
+ // the case if a resolver hook does something bad.
+ if (m_isResolving)
+ {
+ m_felix.releaseGlobalLock();
+ throw new IllegalStateException("Nested resolve operations not allowed.");
+ }
+ m_isResolving = true;
+
+ Map<BundleRevision, List<ResolverWire>> wireMap = null;
+ try
+ {
+ // Make our own copy of revisions.
+ revisions = new HashSet<BundleRevision>(revisions);
+
+ // Extensions are resolved differently.
+ for (Iterator<BundleRevision> it = revisions.iterator(); it.hasNext(); )
+ {
+ BundleImpl bundle = (BundleImpl) it.next().getBundle();
+ if (bundle.isExtension())
+ {
+ it.remove();
+ }
+ }
+
+ // Get resolver hook factories.
+ Set<ServiceReference<ResolverHookFactory>> hookRefs =
+ m_felix.getHooks(ResolverHookFactory.class);
+ if (!hookRefs.isEmpty())
+ {
+ // Create triggers list.
+ Collection<BundleRevision> triggers = Collections.unmodifiableSet(revisions);
+
+ // Create resolver hook objects by calling begin() on factory.
+ for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+ {
+ try
+ {
+ ResolverHookFactory factory = m_felix.getService(m_felix, ref);
+ if (factory != null)
+ {
+ ResolverHook hook = factory.begin(triggers);
+ if (hook != null)
+ {
+ m_hooks.add(hook);
+ }
+ }
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
+
+ // Ask hooks to indicate which revisions should not be resolved.
+ m_whitelist =
+ new ShrinkableCollection<BundleRevision>(
+ m_resolverState.getUnresolvedRevisions());
+ int originalSize = m_whitelist.size();
+ for (ResolverHook hook : m_hooks)
+ {
+ try
+ {
+ hook.filterResolvable(m_whitelist);
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
+ // If nothing was removed, then just null the whitelist
+ // as an optimization.
+ if (m_whitelist.size() == originalSize)
+ {
+ m_whitelist = null;
+ }
+
+ // Check to make sure the target revision is allowed to resolve.
+ if (m_whitelist != null)
+ {
+ revisions.retainAll(m_whitelist);
+ if (revisions.isEmpty())
+ {
+ throw new ResolveException(
+ "Resolver hook prevented resolution.", null, null);
+ }
+ }
+ }
+
+ // Catch any resolve exception to rethrow later because
+ // we may need to call end() on resolver hooks.
+ ResolveException rethrow = null;
+ try
+ {
+ // Resolve the revision.
+// TODO: OSGi R4.3 - Shouldn't we still be passing in greedy attach fragments here?
+ wireMap = m_resolver.resolve(
+ m_resolverState, revisions, m_resolverState.getFragments());
+ }
+ catch (ResolveException ex)
+ {
+ rethrow = ex;
+ }
+
+ // If we have resolver hooks, we must call end() on them.
+ if (!hookRefs.isEmpty())
+ {
+ // Verify that all resolver hook service references are still valid
+ // Call end() on resolver hooks.
+ for (ResolverHook hook : m_hooks)
+ {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+// to their svc ref since we aren't supposed to call end() on unregistered
+// but currently we call end() on all.
+ hook.end();
+ }
+ // Verify that all hook service references are still valid
+ // and unget all resolver hook factories.
+ boolean invalid = false;
+ for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+ {
+ if (ref.getBundle() == null)
+ {
+ invalid = true;
+ }
+ m_felix.ungetService(m_felix, ref);
+ }
+ if (invalid)
+ {
+ throw new BundleException(
+ "Resolver hook service unregistered during resolve.",
+ BundleException.REJECTED_BY_HOOK);
+ }
+ }
+
+ // If the resolve failed, rethrow the exception.
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
+
+ // Otherwise, mark all revisions as resolved.
+ markResolvedRevisions(wireMap);
+ }
+ finally
+ {
+ // Clear resolving flag.
+ m_isResolving = false;
+ // Clear whitelist.
+ m_whitelist = null;
+ // Always clear any hooks.
+ m_hooks.clear();
+ // Always release the global lock.
+ m_felix.releaseGlobalLock();
+ }
+
+ fireResolvedEvents(wireMap);
+ }
+
BundleRevision resolve(BundleRevision revision, String pkgName)
- throws ResolveException
+ throws ResolveException, BundleException
{
BundleRevision provider = null;
@@ -139,6 +457,14 @@ class StatefulResolver
"Unable to acquire global lock for resolve.", revision, null);
}
+ // Make sure we are not already resolving, which can be
+ // the case if a resolver hook does something bad.
+ if (m_isResolving)
+ {
+ throw new IllegalStateException("Nested resolve operations not allowed.");
+ }
+ m_isResolving = true;
+
Map<BundleRevision, List<ResolverWire>> wireMap = null;
try
{
@@ -150,9 +476,117 @@ class StatefulResolver
.getImportedPackageSource(pkgName);
if (provider == null)
{
- wireMap = m_resolver.resolve(
- m_resolverState, revision, pkgName,
- m_resolverState.getFragments());
+ // Get resolver hook factories.
+ Set<ServiceReference<ResolverHookFactory>> hookRefs =
+ m_felix.getHooks(ResolverHookFactory.class);
+ if (!hookRefs.isEmpty())
+ {
+ // Create triggers list.
+ List<BundleRevision> triggers = new ArrayList<BundleRevision>(1);
+ triggers.add(revision);
+ triggers = Collections.unmodifiableList(triggers);
+
+ // Create resolver hook objects by calling begin() on factory.
+ for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+ {
+ try
+ {
+ ResolverHook hook = m_felix.getService(m_felix, ref).begin(triggers);
+ if (hook != null)
+ {
+ m_hooks.add(hook);
+ }
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
+
+ // Ask hooks to indicate which revisions should not be resolved.
+ m_whitelist =
+ new ShrinkableCollection<BundleRevision>(
+ m_resolverState.getUnresolvedRevisions());
+ int originalSize = m_whitelist.size();
+ for (ResolverHook hook : m_hooks)
+ {
+ try
+ {
+ hook.filterResolvable(m_whitelist);
+ }
+ catch (Throwable ex)
+ {
+ throw new BundleException(
+ "Resolver hook exception: " + ex.getMessage(),
+ BundleException.REJECTED_BY_HOOK,
+ ex);
+ }
+ }
+ // If nothing was removed, then just null the whitelist
+ // as an optimization.
+ if (m_whitelist.size() == originalSize)
+ {
+ m_whitelist = null;
+ }
+
+ // Since this is a dynamic import, the root revision is
+ // already resolved, so we don't need to check it against
+ // the whitelist as we do in other cases.
+ }
+
+ // Catch any resolve exception to rethrow later because
+ // we may need to call end() on resolver hooks.
+ ResolveException rethrow = null;
+ try
+ {
+ wireMap = m_resolver.resolve(
+ m_resolverState, revision, pkgName,
+ m_resolverState.getFragments());
+ }
+ catch (ResolveException ex)
+ {
+ rethrow = ex;
+ }
+
+ // If we have resolver hooks, we must call end() on them.
+ if (!hookRefs.isEmpty())
+ {
+ // Verify that all resolver hook service references are still valid
+ // Call end() on resolver hooks.
+ for (ResolverHook hook : m_hooks)
+ {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+// to their svc ref since we aren't supposed to call end() on unregistered
+// but currently we call end() on all.
+ hook.end();
+ }
+ // Verify that all hook service references are still valid
+ // and unget all resolver hook factories.
+ boolean invalid = false;
+ for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+ {
+ if (ref.getBundle() == null)
+ {
+ invalid = true;
+ }
+ m_felix.ungetService(m_felix, ref);
+ }
+ if (invalid)
+ {
+ throw new BundleException(
+ "Resolver hook service unregistered during resolve.",
+ BundleException.REJECTED_BY_HOOK);
+ }
+ }
+
+ // If the resolve failed, rethrow the exception.
+ if (rethrow != null)
+ {
+ throw rethrow;
+ }
if ((wireMap != null) && wireMap.containsKey(revision))
{
@@ -190,6 +624,12 @@ class StatefulResolver
}
finally
{
+ // Clear resolving flag.
+ m_isResolving = false;
+ // Clear whitelist.
+ m_whitelist = null;
+ // Always clear any hooks.
+ m_hooks.clear();
// Always release the global lock.
m_felix.releaseGlobalLock();
}
@@ -225,7 +665,7 @@ class StatefulResolver
for (BundleCapability cap : revision.getWiring().getCapabilities(null))
{
if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
- && cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).equals(pkgName))
+ && cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
{
return false;
}
@@ -242,7 +682,7 @@ class StatefulResolver
// there is a matching one for the package from which we want to
// load a class.
Map<String, Object> attrs = new HashMap(1);
- attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+ attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
BundleRequirementImpl req = new BundleRequirementImpl(
revision,
BundleRevision.PACKAGE_NAMESPACE,
@@ -342,7 +782,7 @@ class StatefulResolver
{
importedPkgs.put(
(String) rw.getCapability().getAttributes()
- .get(BundleCapabilityImpl.PACKAGE_ATTR),
+ .get(BundleRevision.PACKAGE_NAMESPACE),
rw.getProvider());
}
else if (rw.getCapability().getNamespace()
@@ -527,7 +967,7 @@ class StatefulResolver
if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
{
pkgs.add((String)
- cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+ cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
}
}
@@ -577,4 +1017,351 @@ class StatefulResolver
return pkgs;
}
+
+ class ResolverStateImpl implements Resolver.ResolverState
+ {
+ private final Logger m_logger;
+ // 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;
+ // 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(Logger logger, String fwkExecEnvStr)
+ {
+ m_logger = logger;
+ m_revisions = new HashSet<BundleRevision>();
+ m_fragments = new HashSet<BundleRevision>();
+ m_capSets = new HashMap<String, CapabilitySet>();
+
+ 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));
+ }
+
+// TODO: OSGi R4.3/RESOLVER HOOK - We could maintain a separate list to optimize this.
+ synchronized Set<BundleRevision> getUnresolvedRevisions()
+ {
+ Set<BundleRevision> unresolved = new HashSet<BundleRevision>();
+ for (BundleRevision revision : m_revisions)
+ {
+ if (revision.getWiring() == null)
+ {
+ unresolved.add(revision);
+ }
+ }
+ return unresolved;
+ }
+
+ synchronized void addRevision(BundleRevision br)
+ {
+ m_revisions.add(br);
+ List<BundleCapability> caps = (br.getWiring() == null)
+ ? br.getDeclaredCapabilities(null)
+ : br.getWiring().getCapabilities(null);
+ if (caps != null)
+ {
+ for (BundleCapability cap : caps)
+ {
+ CapabilitySet capSet = m_capSets.get(cap.getNamespace());
+ if (capSet == null)
+ {
+ capSet = new CapabilitySet(null, true);
+ m_capSets.put(cap.getNamespace(), capSet);
+ }
+ capSet.addCapability(cap);
+ }
+ }
+
+ if (Util.isFragment(br))
+ {
+ m_fragments.add(br);
+ }
+ }
+
+ synchronized void removeRevision(BundleRevision br)
+ {
+ m_revisions.remove(br);
+ List<BundleCapability> caps = (br.getWiring() == null)
+ ? br.getDeclaredCapabilities(null)
+ : br.getWiring().getCapabilities(null);
+ if (caps != null)
+ {
+ for (BundleCapability cap : caps)
+ {
+ CapabilitySet capSet = m_capSets.get(cap.getNamespace());
+ if (capSet != null)
+ {
+ capSet.removeCapability(cap);
+ }
+ }
+ }
+
+ if (Util.isFragment(br))
+ {
+ m_fragments.remove(br);
+ }
+ }
+
+ synchronized Set<BundleRevision> getFragments()
+ {
+ return new HashSet(m_fragments);
+ }
+
+// TODO: OSGi R4.3 - This will need to be changed once BundleWiring.getCapabilities()
+// is correctly implemented, since it already has to remove substituted caps.
+ synchronized void removeSubstitutedCapabilities(BundleRevision br)
+ {
+ if (br.getWiring() != null)
+ {
+ // Loop through the revision's package wires and determine if any
+ // of them overlap any of the packages exported by the revision.
+ // If so, then the framework must have chosen to have the revision
+ // import rather than export the package, so we need to remove the
+ // corresponding package capability from the package capability set.
+ for (BundleWire w : br.getWiring().getRequiredWires(null))
+ {
+ if (w.getCapability().getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
+ {
+ for (BundleCapability cap : br.getWiring().getCapabilities(null))
+ {
+ if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
+ && w.getCapability().getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
+ .equals(cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)))
+ {
+ m_capSets.get(BundleRevision.PACKAGE_NAMESPACE).removeCapability(cap);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // ResolverState methods.
+ //
+
+ public synchronized SortedSet<BundleCapability> getCandidates(
+ BundleRequirementImpl 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)
+ {
+ Set<BundleCapability> matches = capSet.match(req.getFilter(), obeyMandatory);
+ for (BundleCapability cap : matches)
+ {
+ if (System.getSecurityManager() != null)
+ {
+ if (req.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE) && (
+ !((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())
+ {
+ continue;
+ }
+ }
+ else if (req.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE) && (
+ !((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))
+ )))
+ {
+ continue;
+ }
+ else if (req.getNamespace().equals(BundleRevision.HOST_NAMESPACE) &&
+ (!((BundleProtectionDomain) reqRevision.getProtectionDomain())
+ .impliesDirect(new BundlePermission(
+ reqRevision.getSymbolicName(),
+ BundlePermission.FRAGMENT))
+ || !((BundleProtectionDomain) ((BundleRevisionImpl) cap.getRevision()).getProtectionDomain())
+ .impliesDirect(new BundlePermission(
+ cap.getRevision().getSymbolicName(),
+ BundlePermission.HOST))))
+ {
+ continue;
+ }
+ }
+
+ 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.
+// TODO: OSGi R4.3 - It would be better if we could think of a way to do this
+// filtering that was less costly. One possibility it to do the check in
+// ResolverState.checkExecutionEnvironment(), since it will only need to
+// be done once for any black listed revision. However, as we move toward
+// OBR-like API, this is a non-standard call, so doing it here is the only
+// standard way of achieving it.
+ 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)
+ {
+ hook.filterMatches(req, shrinkable);
+ }
+ }
+
+ return result;
+ }
+
+ 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.
+// TODO: OSGi R4.3 - Is it sufficient to just check declared native libs here?
+// List<R4Library> libs = ((BundleWiringImpl) revision.getWiring()).getNativeLibraries();
+ 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);
+ }
+ }
+ }
+ }
+
+ //
+ // Utility methods.
+ //
+
+ /**
+ * Updates the framework wide execution environment string and a cached Set of
+ * execution environment tokens from the comma delimited list specified by the
+ * system variable 'org.osgi.framework.executionenvironment'.
+ * @param fwkExecEnvStr Comma delimited string of provided execution environments
+ * @return the parsed set of execution environments
+ **/
+ private static Set<String> parseExecutionEnvironments(String fwkExecEnvStr)
+ {
+ Set<String> newSet = new HashSet<String>();
+ if (fwkExecEnvStr != null)
+ {
+ StringTokenizer tokens = new StringTokenizer(fwkExecEnvStr, ",");
+ while (tokens.hasMoreTokens())
+ {
+ newSet.add(tokens.nextToken().trim());
+ }
+ }
+ return newSet;
+ }
}
\ No newline at end of file
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/CandidateComparator.java Wed Jun 15 18:57:20 2011
@@ -47,8 +47,8 @@ public class CandidateComparator impleme
// Compare revision capabilities.
if ((c == 0) && cap1.getNamespace().equals(BundleRevision.BUNDLE_NAMESPACE))
{
- c = ((Comparable) cap1.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
- .compareTo(cap2.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE));
+ c = ((Comparable) cap1.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE))
+ .compareTo(cap2.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE));
if (c == 0)
{
Version v1 = (!cap1.getAttributes().containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE))
@@ -65,8 +65,8 @@ public class CandidateComparator impleme
// Compare package capabilities.
else if ((c == 0) && cap1.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
{
- c = ((Comparable) cap1.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR))
- .compareTo(cap2.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+ c = ((Comparable) cap1.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE))
+ .compareTo(cap2.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
if (c == 0)
{
Version v1 = (!cap1.getAttributes().containsKey(BundleCapabilityImpl.VERSION_ATTR))