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 [2/2] - in /felix/trunk/framework/src/main/java/org/apache/felix/framework: ./ resolver/ util/ util/manifestparser/ wiring/

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java Wed Jun 15 18:57:20 2011
@@ -31,10 +31,8 @@ import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import org.apache.felix.framework.BundleRevisionImpl;
-import org.apache.felix.framework.BundleWiringImpl;
 import org.apache.felix.framework.resolver.Resolver.ResolverState;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
 import org.apache.felix.framework.wiring.BundleRequirementImpl;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
@@ -44,10 +42,8 @@ import org.osgi.framework.wiring.BundleR
 
 class Candidates
 {
-    private final BundleRevision m_root;
-
-    // Set of all candidate bundle revisions.
-    private final Set<BundleRevision> m_candidateRevisions;
+    // Set of all involved bundle revisions.
+    private final Set<BundleRevision> m_involvedRevisions;
     // Maps a capability to requirements that match it.
     private final Map<BundleCapability, Set<BundleRequirement>> m_dependentMap;
     // Maps a requirement to the capability it matches.
@@ -69,23 +65,20 @@ class Candidates
 
     /**
      * Private copy constructor used by the copy() method.
-     * @param root the root module for the resolve.
      * @param dependentMap the capability dependency map.
      * @param candidateMap the requirement candidate map.
      * @param hostFragments the fragment map.
      * @param wrappedHosts the wrapped hosts map.
     **/
     private Candidates(
-        BundleRevision root,
-        Set<BundleRevision> candidateRevisions,
+        Set<BundleRevision> involvedRevisions,
         Map<BundleCapability, Set<BundleRequirement>> dependentMap,
         Map<BundleRequirement, SortedSet<BundleCapability>> candidateMap,
         Map<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>> hostFragments,
         Map<BundleRevision, HostBundleRevision> wrappedHosts, Map<BundleRevision, Object> populateResultCache,
         boolean fragmentsPresent)
     {
-        m_root = root;
-        m_candidateRevisions = candidateRevisions;
+        m_involvedRevisions = involvedRevisions;
         m_dependentMap = dependentMap;
         m_candidateMap = candidateMap;
         m_hostFragments = hostFragments;
@@ -95,49 +88,17 @@ class Candidates
     }
 
     /**
-     * Constructs a new populated Candidates object for the specified root module.
-     * @param state the resolver state used for populating the candidates.
-     * @param root the root module for the resolve.
-    **/
-    public Candidates(ResolverState state, BundleRevision root)
-    {
-        m_root = root;
-        m_candidateRevisions = new HashSet<BundleRevision>();
-        m_dependentMap = new HashMap<BundleCapability, Set<BundleRequirement>>();
-        m_candidateMap = new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
-        m_hostFragments =
-            new HashMap<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>();
-        m_allWrappedHosts = new HashMap<BundleRevision, HostBundleRevision>();
-        m_populateResultCache = new HashMap<BundleRevision, Object>();
-
-        populate(state, m_root);
-    }
-
-    /**
-     * Constructs a new populated Candidates object with the specified root module and
-     * starting requirement and matching candidates. This constructor is used
-     * when the root module is performing a dynamic import for the given
-     * requirement and the given potential candidates.
-     * @param state the resolver state used for populating the candidates.
-     * @param root the module with a dynamic import to resolve.
-     * @param req the requirement being resolved.
-     * @param candidates the potential candidates matching the requirement.
+     * Constructs an empty Candidates object.
     **/
-    public Candidates(ResolverState state, BundleRevision root,
-        BundleRequirement req, SortedSet<BundleCapability> candidates)
+    public Candidates()
     {
-        m_root = root;
-        m_candidateRevisions = new HashSet<BundleRevision>();
+        m_involvedRevisions = new HashSet<BundleRevision>();
         m_dependentMap = new HashMap<BundleCapability, Set<BundleRequirement>>();
         m_candidateMap = new HashMap<BundleRequirement, SortedSet<BundleCapability>>();
         m_hostFragments =
             new HashMap<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>();
         m_allWrappedHosts = new HashMap<BundleRevision, HostBundleRevision>();
         m_populateResultCache = new HashMap<BundleRevision, Object>();
-
-        add(req, candidates);
-
-        populateDynamic(state, m_root);
     }
 
     /**
@@ -314,6 +275,9 @@ class Candidates
         }
         else if (cycleCount.intValue() == 0)
         {
+            // Record invoved revision.
+            m_involvedRevisions.add(revision);
+
             // Record that the revision was successfully populated.
             m_populateResultCache.put(revision, Boolean.TRUE);
 
@@ -325,26 +289,31 @@ class Candidates
         }
     }
 
-    public final void populateOptional(ResolverState state, BundleRevision revision)
-    {
-        // We will always attempt to populate optional fragments, since this
-        // is necessary for greedy resolving of fragment. Howevere, we'll only
-        // attempt to populate optional non-fragment revisions if they aren't
-        // already resolved.
+// TODO: OSGi R4.3 - Related to resolve() method clean up, can this just
+//       become the normal case? Currently, it just swallows the resolve
+//       exception, which would have to change.
+    public final boolean populate(
+        ResolverState state, BundleRevision revision, boolean isGreedyAttach)
+    {
+        // We will always attempt to populate fragments, since this is necessary
+        // for greedy attaching of fragment. However, we'll only attempt to
+        // populate optional non-fragment revisions if they aren't already
+        // resolved.
         boolean isFragment = Util.isFragment(revision);
         if (!isFragment && (revision.getWiring() != null))
         {
-            return;
+            return false;
         }
 
         try
         {
-            // If the optional revision is a fragment, then we only want to populate
-            // the fragment if it has a candidate host in the set of already populated
-            // revisions. We do this to avoid unnecessary work in prepare(). If the
-            // fragment has a host, we'll prepopulate the result cache here to avoid
-            // having to do the host lookup again in populate().
-            if (isFragment)
+            // If the optional revision is a fragment and this is a greedy attach,
+            // then only populate the fragment if it has a candidate host in the
+            // set of already populated revisions. We do this to avoid resolving
+            // unneeded fragments and hosts. If the fragment has a host, we'll
+            // prepopulate the result cache here to avoid having to do the host
+            // lookup again in populate().
+            if (isGreedyAttach && isFragment)
             {
                 // Get the current result cache value, to make sure the revision
                 // hasn't already been populated.
@@ -385,7 +354,7 @@ class Candidates
                     // return since this fragment isn't needed.
                     if (hosts.isEmpty())
                     {
-                        return;
+                        return false;
                     }
 
                     // If there are populates host candidates, then finish up
@@ -423,26 +392,37 @@ class Candidates
         }
         catch (ResolveException ex)
         {
-            // Ignore since the revision is optional.
+            return false;
         }
+
+        return true;
     }
 
-    private boolean isPopulated(BundleRevision revision)
+    public boolean isPopulated(BundleRevision revision)
     {
         Object value = m_populateResultCache.get(revision);
         return ((value != null) && (value instanceof Boolean));
     }
 
-    private void populateDynamic(ResolverState state, BundleRevision revision)
+    public ResolveException getResolveException(BundleRevision revision)
     {
-        // There should be one entry in the candidate map, which are the
-        // the candidates for the matching dynamic requirement. Get the
-        // matching candidates and populate their candidates if necessary.
+        Object value = m_populateResultCache.get(revision);
+        return ((value != null) && (value instanceof ResolveException))
+            ? (ResolveException) value : null;
+    }
+
+    public void populateDynamic(
+        ResolverState state, BundleRevision revision,
+        BundleRequirement req, SortedSet<BundleCapability> candidates)
+    {
+        // Add the dynamic imports candidates.
+// TODO: OSGi R4.3 - Can we just calculate the candidates inside here too?
+//       I think we don't because of performance reasons since we have to
+//       look them up already. If so, maybe it is not worth doing it here.
+        add(req, candidates);
+
+        // Populate the candidates for the dynamic import.
         ResolveException rethrow = null;
-        Entry<BundleRequirement, SortedSet<BundleCapability>> entry =
-            m_candidateMap.entrySet().iterator().next();
-        BundleRequirement dynReq = entry.getKey();
-        SortedSet<BundleCapability> candidates = entry.getValue();
         for (Iterator<BundleCapability> itCandCap = candidates.iterator();
             itCandCap.hasNext(); )
         {
@@ -468,10 +448,12 @@ class Candidates
         {
             if (rethrow == null)
             {
-                rethrow = new ResolveException("Dynamic import failed.", revision, dynReq);
+                rethrow = new ResolveException("Dynamic import failed.", revision, req);
             }
             throw rethrow;
         }
+
+        m_populateResultCache.put(revision, Boolean.TRUE);
     }
 
     /**
@@ -492,16 +474,6 @@ class Candidates
 
         // Record the candidates.
         m_candidateMap.put(req, candidates);
-
-        // Make a list of all candidate revisions for determining singetons.
-        // Add the requirement as a dependent on the candidates. Keep track
-        // of fragments for hosts.
-        for (BundleCapability cap : candidates)
-        {
-            // Remember the revision for all capabilities so we can
-            // determine which ones are singletons.
-            m_candidateRevisions.add(cap.getRevision());
-        }
     }
 
     /**
@@ -569,7 +541,7 @@ class Candidates
 
         final Map<String, BundleRevision> singletons = new HashMap<String, BundleRevision>();
 
-        for (Iterator<BundleRevision> it = m_candidateRevisions.iterator(); it.hasNext(); )
+        for (Iterator<BundleRevision> it = m_involvedRevisions.iterator(); it.hasNext(); )
         {
             BundleRevision br = it.next();
             if (isSingleton(br))
@@ -597,18 +569,25 @@ class Candidates
                     // if it wasn't selected.
                     if (singleton != null)
                     {
-                        removeRevision(singleton);
+                        removeRevision(
+                            singleton,
+                            new ResolveException(
+                                "Conflict with another singleton.", singleton, null));
                     }
                 }
                 else
                 {
-                    removeRevision(br);
+                    removeRevision(br,
+                        new ResolveException(
+                            "Conflict with another singleton.", br, null));
                 }
             }
         }
 
         // If the root is a singleton, then prefer it over any other singleton.
-        if (isSingleton(m_root))
+// TODO: OSGi R4.3/SINGLETON - How do we prefer the root as a singleton?
+/*
+        if ((m_root != null) && isSingleton(m_root))
         {
             BundleRevision singleton = singletons.get(m_root.getSymbolicName());
             singletons.put(m_root.getSymbolicName(), m_root);
@@ -627,6 +606,7 @@ class Candidates
                 removeRevision(singleton);
             }
         }
+*/
 
         // Make sure selected singletons do not conflict with existing
         // singletons passed into this method.
@@ -637,7 +617,9 @@ class Candidates
             if ((singleton != null) && (singleton != existing))
             {
                 singletons.remove(singleton.getSymbolicName());
-                removeRevision(singleton);
+                removeRevision(singleton,
+                    new ResolveException(
+                        "Conflict with another singleton.", singleton, null));
             }
         }
 
@@ -712,7 +694,9 @@ class Candidates
         // Step 3
         for (BundleRevision br : unselectedFragments)
         {
-            removeRevision(br);
+            removeRevision(br,
+                new ResolveException(
+                    "Fragment was not selected for attachment.", br, null));
         }
 
         // Step 4
@@ -722,15 +706,20 @@ class Candidates
             // from the merged host.
             for (BundleCapability c : hostRevision.getDeclaredCapabilities(null))
             {
-                Set<BundleRequirement> dependents =
-                    m_dependentMap.get(((HostedCapability) c).getDeclaredCapability());
-                if (dependents != null)
-                {
-                    for (BundleRequirement r : dependents)
+                // Don't replace the host capability, since the fragment will
+                // really be attached to the original host, not the wrapper.
+                if (!c.getNamespace().equals(BundleRevision.HOST_NAMESPACE))
+                {
+                    Set<BundleRequirement> dependents =
+                        m_dependentMap.get(((HostedCapability) c).getDeclaredCapability());
+                    if (dependents != null)
                     {
-                        Set<BundleCapability> cands = m_candidateMap.get(r);
-                        cands.remove(((HostedCapability) c).getDeclaredCapability());
-                        cands.add(c);
+                        for (BundleRequirement r : dependents)
+                        {
+                            Set<BundleCapability> cands = m_candidateMap.get(r);
+                            cands.remove(((HostedCapability) c).getDeclaredCapability());
+                            cands.add(c);
+                        }
                     }
                 }
             }
@@ -806,17 +795,14 @@ class Candidates
      * @param revision the module to remove.
      * @throws ResolveException if removing the module caused the resolve to fail.
     **/
-    private void removeRevision(BundleRevision revision) throws ResolveException
+    private void removeRevision(BundleRevision revision, ResolveException ex)
     {
-        if (m_root.equals(revision))
-        {
-// TODO: SINGLETON RESOLVER - Improve this message.
-            String msg = "Unable to resolve " + m_root;
-            ResolveException ex = new ResolveException(msg, m_root, null);
-            throw ex;
-        }
+        // Add removal reason to result cache.
+        m_populateResultCache.put(revision, ex);
+        // Remove from dependents.
         Set<BundleRevision> unresolvedRevisions = new HashSet<BundleRevision>();
         remove(revision, unresolvedRevisions);
+        // Remove dependents that failed as a result of removing revision.
         while (!unresolvedRevisions.isEmpty())
         {
             Iterator<BundleRevision> it = unresolvedRevisions.iterator();
@@ -928,13 +914,10 @@ class Candidates
                     m_candidateMap.remove(r);
                     if (!((BundleRequirementImpl) r).isOptional())
                     {
-                        if (m_root.equals(r.getRevision()))
-                        {
-                            String msg = "Unable to resolve " + m_root
-                                + ": missing requirement " + r;
-                            ResolveException ex = new ResolveException(msg, m_root, r);
-                            throw ex;
-                        }
+                        String msg = "Unable to resolve " + r.getRevision()
+                            + ": missing requirement " + r;
+                        m_populateResultCache.put(
+                            r.getRevision(), new ResolveException(msg, r.getRevision(), r));
                         unresolvedRevisions.add(r.getRevision());
                     }
                 }
@@ -968,7 +951,7 @@ class Candidates
         }
 
         return new Candidates(
-            m_root, m_candidateRevisions, dependentMap, candidateMap,
+            m_involvedRevisions, dependentMap, candidateMap,
             m_hostFragments, m_allWrappedHosts, m_populateResultCache,
             m_fragmentsPresent);
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/HostedCapability.java Wed Jun 15 18:57:20 2011
@@ -113,7 +113,9 @@ public class HostedCapability extends Bu
         if (getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
         {
             return "[" + m_host + "] "
-                + getNamespace() + "; " + getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+                + getNamespace()
+                + "; "
+                + getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
         }
         return "[" + m_host + "] " + getNamespace() + "; " + getAttributes();
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/Resolver.java Wed Jun 15 18:57:20 2011
@@ -31,6 +31,8 @@ public interface Resolver
     Map<BundleRevision, List<ResolverWire>> resolve(
         ResolverState state, BundleRevision revision, Set<BundleRevision> optional);
     Map<BundleRevision, List<ResolverWire>> resolve(
+        ResolverState state, Set<BundleRevision> revisions, Set<BundleRevision> optional);
+    Map<BundleRevision, List<ResolverWire>> resolve(
         ResolverState state, BundleRevision revision, String pkgName,
         Set<BundleRevision> fragments);
 

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java Wed Jun 15 18:57:20 2011
@@ -71,17 +71,25 @@ public class ResolverImpl implements Res
 
                 try
                 {
-                    // Populate all candidates.
-                    Candidates allCandidates = new Candidates(state, revision);
+                    // Populate revision's candidates.
+                    Candidates allCandidates = new Candidates();
+                    allCandidates.populate(state, revision);
 
                     // Try to populate optional fragments.
                     for (BundleRevision br : optional)
                     {
-                        allCandidates.populateOptional(state, br);
+                        allCandidates.populate(state, br, true);
                     }
 
                     // Merge any fragments into hosts.
                     allCandidates.prepare(getResolvedSingletons(state));
+                    // Make sure revision is still valid, since it could
+                    // fail due to fragment and/or singleton selection.
+// TODO: OSGi R4.3 - Could this be merged back into Candidates?
+                    if (!allCandidates.isPopulated(revision))
+                    {
+                        throw allCandidates.getResolveException(revision);
+                    }
 
                     // Record the initial candidate permutation.
                     m_usesPermutations.add(allCandidates);
@@ -183,6 +191,182 @@ public class ResolverImpl implements Res
     }
 
     public Map<BundleRevision, List<ResolverWire>> resolve(
+        ResolverState state, Set<BundleRevision> revisions, Set<BundleRevision> optional)
+    {
+        Map<BundleRevision, List<ResolverWire>> wireMap = new HashMap<BundleRevision, List<ResolverWire>>();
+        Map<BundleRevision, Packages> revisionPkgMap = new HashMap<BundleRevision, Packages>();
+
+        boolean retry;
+        do
+        {
+            retry = false;
+
+            try
+            {
+                // Create object to hold all candidates.
+                Candidates allCandidates = new Candidates();
+
+                // Populate revisions.
+                for (Iterator<BundleRevision> it = revisions.iterator(); it.hasNext(); )
+                {
+                    BundleRevision br = it.next();
+// TODO: OSGi R4.3 - This is not correct for fragments, since they may have wires already
+//       but we still need to resolve them.
+                    if ((br.getWiring() != null) || !allCandidates.populate(state, br, false))
+                    {
+                        it.remove();
+                    }
+                }
+
+                // Try to populate optional fragments.
+                for (BundleRevision br : optional)
+                {
+                    allCandidates.populate(state, br, true);
+                }
+
+                // Merge any fragments into hosts.
+                allCandidates.prepare(getResolvedSingletons(state));
+
+                // Prune failed revisions.
+// TODO: OSGi R4.3 - Again, can we merge this stuff into Candidates?
+//                for (Iterator<BundleRevision> it = revisions.iterator(); it.hasNext(); )
+//                {
+//                    if (!allCandidates.isPopulated(it.next()))
+//                    {
+//                        it.remove();
+//                    }
+//                }
+
+                // Record the initial candidate permutation.
+                m_usesPermutations.add(allCandidates);
+
+                ResolveException rethrow = null;
+
+                // If the requested revision is a fragment, then
+                // ultimately we will verify the host., so store
+                // any host requirements
+                Map<BundleRevision, List<BundleRequirement>> hostReqs =
+                    new HashMap<BundleRevision, List<BundleRequirement>>();
+                for (BundleRevision br : revisions)
+                {
+                    hostReqs.put(
+                        br, br.getDeclaredRequirements(BundleRevision.HOST_NAMESPACE));
+                }
+
+                do
+                {
+                    rethrow = null;
+
+                    revisionPkgMap.clear();
+                    m_packageSourcesCache.clear();
+
+                    allCandidates = (m_usesPermutations.size() > 0)
+                        ? m_usesPermutations.remove(0)
+                        : m_importPermutations.remove(0);
+//allCandidates.dump();
+
+                    for (BundleRevision br : revisions)
+                    {
+                        BundleRevision target = br;
+
+                        // If we are resolving a fragment, then we
+                        // actually want to verify its host.
+                        List<BundleRequirement> hostReq = hostReqs.get(br);
+                        if (!hostReq.isEmpty())
+                        {
+                            target = allCandidates.getCandidates(hostReq.get(0))
+                                .iterator().next().getRevision();
+                        }
+
+                        calculatePackageSpaces(
+                            allCandidates.getWrappedHost(target), allCandidates, revisionPkgMap,
+                            new HashMap(), new HashSet());
+//System.out.println("+++ PACKAGE SPACES START +++");
+//dumpRevisionPkgMap(revisionPkgMap);
+//System.out.println("+++ PACKAGE SPACES END +++");
+
+                        try
+                        {
+                            checkPackageSpaceConsistency(
+                                false, allCandidates.getWrappedHost(target),
+                                allCandidates, revisionPkgMap, new HashMap());
+                        }
+                        catch (ResolveException ex)
+                        {
+                            rethrow = ex;
+                        }
+                    }
+                }
+                while ((rethrow != null)
+                    && ((m_usesPermutations.size() > 0) || (m_importPermutations.size() > 0)));
+
+                // If there is a resolve exception, then determine if an
+                // optionally resolved revision is to blame (typically a fragment).
+                // If so, then remove the optionally resolved resolved and try
+                // again; otherwise, rethrow the resolve exception.
+                if (rethrow != null)
+                {
+                    BundleRevision faultyRevision =
+                        getActualBundleRevision(rethrow.getRevision());
+                    if (rethrow.getRequirement() instanceof HostedRequirement)
+                    {
+                        faultyRevision =
+                            ((HostedRequirement) rethrow.getRequirement())
+                                .getDeclaredRequirement().getRevision();
+                    }
+                    if (revisions.remove(faultyRevision))
+                    {
+                        retry = true;
+                    }
+                    else if (optional.remove(faultyRevision))
+                    {
+                        retry = true;
+                    }
+                    else
+                    {
+                        throw rethrow;
+                    }
+                }
+                // If there is no exception to rethrow, then this was a clean
+                // resolve, so populate the wire map.
+                else
+                {
+                    for (BundleRevision br : revisions)
+                    {
+                        BundleRevision target = br;
+
+                        // If we are resolving a fragment, then we
+                        // actually want to populate its host's wires.
+                        List<BundleRequirement> hostReq = hostReqs.get(br);
+                        if (!hostReq.isEmpty())
+                        {
+                            target = allCandidates.getCandidates(hostReq.get(0))
+                                .iterator().next().getRevision();
+                        }
+
+                        if (allCandidates.isPopulated(target))
+                        {
+                            wireMap =
+                                populateWireMap(
+                                    allCandidates.getWrappedHost(target),
+                                    revisionPkgMap, wireMap, allCandidates);
+                        }
+                    }
+                }
+            }
+            finally
+            {
+                // Always clear the state.
+                m_usesPermutations.clear();
+                m_importPermutations.clear();
+            }
+        }
+        while (retry);
+
+        return wireMap;
+    }
+
+    public Map<BundleRevision, List<ResolverWire>> resolve(
         ResolverState state, BundleRevision revision, String pkgName,
         Set<BundleRevision> optional)
     {
@@ -212,11 +396,18 @@ public class ResolverImpl implements Res
                     // Try to populate optional fragments.
                     for (BundleRevision br : optional)
                     {
-                        allCandidates.populateOptional(state, br);
+                        allCandidates.populate(state, br, true);
                     }
 
                     // Merge any fragments into hosts.
                     allCandidates.prepare(getResolvedSingletons(state));
+                    // Make sure revision is still valid, since it could
+                    // fail due to fragment and/or singleton selection.
+// TODO: OSGi R4.3 - Could this be merged back into Candidates?
+                    if (!allCandidates.isPopulated(revision))
+                    {
+                        throw allCandidates.getResolveException(revision);
+                    }
 
                     // Record the initial candidate permutation.
                     m_usesPermutations.add(allCandidates);
@@ -349,7 +540,7 @@ public class ResolverImpl implements Res
         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 null;
             }
@@ -366,7 +557,7 @@ public class ResolverImpl implements Res
         // 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,
@@ -417,7 +608,8 @@ public class ResolverImpl implements Res
 
         if (candidates.size() > 0)
         {
-            allCandidates = new Candidates(state, revision, dynReq, candidates);
+            allCandidates = new Candidates();
+            allCandidates.populateDynamic(state, revision, dynReq, candidates);
         }
 
         return allCandidates;
@@ -682,7 +874,7 @@ public class ResolverImpl implements Res
             // for imported or required packages, appropriately.
 
             String pkgName = (String)
-                candCap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+                candCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
 
             List blameReqs = new ArrayList();
             blameReqs.add(currentReq);
@@ -1147,7 +1339,7 @@ public class ResolverImpl implements Res
             if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
             {
                 exports.put(
-                    (String) cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR),
+                    (String) cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE),
                     cap);
             }
         }
@@ -1165,7 +1357,7 @@ public class ResolverImpl implements Res
                         BundleRevision.PACKAGE_NAMESPACE))
                     {
                         String pkgName = (String) wire.getCapability()
-                            .getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+                            .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
                         exports.remove(pkgName);
                     }
                 }
@@ -1181,7 +1373,7 @@ public class ResolverImpl implements Res
                         if ((cands != null) && !cands.isEmpty())
                         {
                             String pkgName = (String) cands.iterator().next()
-                                .getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
+                                .getAttributes().get(BundleRevision.PACKAGE_NAMESPACE);
                             exports.remove(pkgName);
                         }
                     }
@@ -1267,7 +1459,7 @@ public class ResolverImpl implements Res
 
             // Get the package name associated with the capability.
             String pkgName = cap.getAttributes()
-                .get(BundleCapabilityImpl.PACKAGE_ATTR).toString();
+                .get(BundleRevision.PACKAGE_NAMESPACE).toString();
 
             // Since a revision can export the same package more than once, get
             // all package capabilities for the specified package name.
@@ -1277,7 +1469,7 @@ public class ResolverImpl implements Res
             for (int capIdx = 0; capIdx < caps.size(); capIdx++)
             {
                 if (caps.get(capIdx).getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE)
-                    && caps.get(capIdx).getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).equals(pkgName))
+                    && caps.get(capIdx).getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).equals(pkgName))
                 {
                     sources.add(caps.get(capIdx));
                 }
@@ -1423,7 +1615,7 @@ public class ResolverImpl implements Res
             {
                 // Ignore revisions that import themselves.
                 if (!revision.equals(blame.m_cap.getRevision())
-                    && blame.m_cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)
+                    && blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
                         .equals(pkgName))
                 {
                     if (blame.m_cap.getRevision().getWiring() == null)
@@ -1434,7 +1626,7 @@ public class ResolverImpl implements Res
 
                     Packages candPkgs = revisionPkgMap.get(blame.m_cap.getRevision());
                     Map<String, Object> attrs = new HashMap(1);
-                    attrs.put(BundleCapabilityImpl.PACKAGE_ATTR, pkgName);
+                    attrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
                     packageWires.add(
                         new ResolverWireImpl(
                             revision,
@@ -1530,9 +1722,9 @@ public class ResolverImpl implements Res
                         (BundleRequirementImpl) blame.m_reqs.get(i));
                     if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
                     {
-                        sb.append(BundleCapabilityImpl.PACKAGE_ATTR);
+                        sb.append(BundleRevision.PACKAGE_NAMESPACE);
                         sb.append("=");
-                        sb.append(cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).toString());
+                        sb.append(cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString());
                         BundleCapability usedCap;
                         if ((i + 2) < blame.m_reqs.size())
                         {
@@ -1547,7 +1739,7 @@ public class ResolverImpl implements Res
                                 (BundleRequirementImpl) blame.m_reqs.get(i + 1));
                         }
                         sb.append("; uses:=");
-                        sb.append(usedCap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+                        sb.append(usedCap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
                     }
                     else
                     {
@@ -1560,18 +1752,18 @@ public class ResolverImpl implements Res
                     BundleCapability export = Util.getSatisfyingCapability(
                         blame.m_cap.getRevision(),
                         (BundleRequirementImpl) blame.m_reqs.get(i));
-                    sb.append(BundleCapabilityImpl.PACKAGE_ATTR);
+                    sb.append(BundleRevision.PACKAGE_NAMESPACE);
                     sb.append("=");
-                    sb.append(export.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).toString());
-                    if (!export.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)
-                        .equals(blame.m_cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)))
+                    sb.append(export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString());
+                    if (!export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
+                        .equals(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)))
                     {
                         sb.append("; uses:=");
-                        sb.append(blame.m_cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+                        sb.append(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
                         sb.append("\n    export: ");
-                        sb.append(BundleCapabilityImpl.PACKAGE_ATTR);
+                        sb.append(BundleRevision.PACKAGE_NAMESPACE);
                         sb.append("=");
-                        sb.append(blame.m_cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR).toString());
+                        sb.append(blame.m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString());
                     }
                     sb.append("\n  ");
                     sb.append(blame.m_cap.getRevision().getSymbolicName());
@@ -1617,7 +1809,7 @@ public class ResolverImpl implements Res
         public String toString()
         {
             return m_cap.getRevision()
-                + "." + m_cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR)
+                + "." + m_cap.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE)
                 + (((m_reqs == null) || m_reqs.isEmpty())
                     ? " NO BLAME"
                     : " BLAMED ON " + m_reqs);

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ShrinkableCollection.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ShrinkableCollection.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ShrinkableCollection.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ShrinkableCollection.java Wed Jun 15 18:57:20 2011
@@ -24,21 +24,21 @@ import java.util.Iterator;
 /** This collection wraps any other collection but prohibits calls to add
  *  elements to the collection.
  */
-public class ShrinkableCollection implements Collection
+public class ShrinkableCollection<T> implements Collection<T>
 {
-    private final Collection m_delegate;
+    private final Collection<T> m_delegate;
 
-    public ShrinkableCollection(Collection delegate)
+    public ShrinkableCollection(Collection<T> delegate)
     {
         m_delegate = delegate;
     }
 
-    public boolean add(Object o)
+    public boolean add(T o)
     {
         throw new UnsupportedOperationException();
     }
 
-    public boolean addAll(Collection c)
+    public boolean addAll(Collection<? extends T> c)
     {
         throw new UnsupportedOperationException();
     }
@@ -53,16 +53,18 @@ public class ShrinkableCollection implem
         return m_delegate.contains(o);
     }
 
-    public boolean containsAll(Collection c)
+    public boolean containsAll(Collection<?> c)
     {
         return m_delegate.containsAll(c);
     }
 
+    @Override
     public boolean equals(Object o)
     {
         return m_delegate.equals(o);
     }
 
+    @Override
     public int hashCode()
     {
         return m_delegate.hashCode();
@@ -83,12 +85,12 @@ public class ShrinkableCollection implem
         return m_delegate.remove(o);
     }
 
-    public boolean removeAll(Collection c)
+    public boolean removeAll(Collection<?> c)
     {
         return m_delegate.removeAll(c);
     }
 
-    public boolean retainAll(Collection c)
+    public boolean retainAll(Collection<?> c)
     {
         return m_delegate.retainAll(c);
     }
@@ -103,7 +105,7 @@ public class ShrinkableCollection implem
         return m_delegate.toArray();
     }
 
-    public Object[] toArray(Object[] a)
+    public <A> A[] toArray(A[] a)
     {
         return m_delegate.toArray(a);
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java Wed Jun 15 18:57:20 2011
@@ -358,7 +358,7 @@ public class Util
                     if (w.getCapability().getNamespace()
                             .equals(BundleRevision.PACKAGE_NAMESPACE) &&
                         w.getCapability().getAttributes()
-                            .get(BundleCapabilityImpl.PACKAGE_ATTR).equals(name))
+                            .get(BundleRevision.PACKAGE_NAMESPACE).equals(name))
                     {
                         return w;
                     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java Wed Jun 15 18:57:20 2011
@@ -95,11 +95,11 @@ public class ManifestParser
         // Parse bundle symbolic name.
         //
 
-        BundleCapabilityImpl requireCap = parseBundleSymbolicName(owner, m_headerMap);
-        if (requireCap != null)
+        BundleCapabilityImpl bundleCap = parseBundleSymbolicName(owner, m_headerMap);
+        if (bundleCap != null)
         {
             m_bundleSymbolicName = (String)
-                requireCap.getAttributes().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+                bundleCap.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE);
 
             // Add a bundle capability and a host capability to all
             // non-fragment bundles. A host capability is the same
@@ -109,12 +109,15 @@ public class ManifestParser
             // dependencies.
             if (headerMap.get(Constants.FRAGMENT_HOST) == null)
             {
-                capList.add(requireCap);
+                capList.add(bundleCap);
+                Map<String, Object> hostAttrs =
+                    new HashMap<String, Object>(bundleCap.getAttributes());
+                Object value = hostAttrs.remove(BundleRevision.BUNDLE_NAMESPACE);
+                hostAttrs.put(BundleRevision.HOST_NAMESPACE, value);
                 capList.add(new BundleCapabilityImpl(
                     owner, BundleRevision.HOST_NAMESPACE,
                     Collections.EMPTY_MAP,
-// TODO: OSGi R4.3 - Wraps map as unmodifiable twice.
-                    requireCap.getAttributes()));
+                    hostAttrs));
             }
 
             // Add a singleton capability if the bundle is a singleton.
@@ -123,13 +126,16 @@ public class ManifestParser
             // attach this information to the bundle or host capabilities
             // because fragments don't have those capabilities, but fragments
             // can be singletons too.
-            if (isSingleton(requireCap))
+            if (isSingleton(bundleCap))
             {
+                Map<String, Object> singletonAttrs =
+                    new HashMap<String, Object>(bundleCap.getAttributes());
+                Object value = singletonAttrs.remove(BundleRevision.BUNDLE_NAMESPACE);
+                singletonAttrs.put(BundleCapabilityImpl.SINGLETON_NAMESPACE, value);
                 capList.add(new BundleCapabilityImpl(
                     owner, BundleCapabilityImpl.SINGLETON_NAMESPACE,
                     Collections.EMPTY_MAP,
-// TODO: OSGi R4.3 - Wraps map as unmodifiable twice.
-                    requireCap.getAttributes()));
+                    singletonAttrs));
             }
         }
 
@@ -418,7 +424,7 @@ public class ManifestParser
 //       notion where namespace is also the name of the key attribute.
                 Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
                 newAttrs.put(
-                    BundleCapabilityImpl.PACKAGE_ATTR,
+                    BundleRevision.PACKAGE_NAMESPACE,
                     path);
                 newAttrs.putAll(attrs);
 
@@ -812,7 +818,7 @@ public class ManifestParser
                 Map<String, Object> attrs = clause.m_attrs;
                 Map<String, Object> newAttrs = new HashMap<String, Object>(attrs.size() + 1);
                 newAttrs.put(
-                    BundleCapabilityImpl.PACKAGE_ATTR,
+                    BundleRevision.PACKAGE_NAMESPACE,
                     pkgName);
                 newAttrs.putAll(attrs);
 
@@ -1124,7 +1130,7 @@ public class ManifestParser
         for (int i = 0; i < exports.size(); i++)
         {
             if (map.get(exports.get(i).getAttributes()
-                .get(BundleCapabilityImpl.PACKAGE_ATTR)) == null)
+                .get(BundleRevision.PACKAGE_NAMESPACE)) == null)
             {
                 // Convert Version to VersionRange.
                 Map<String, Object> attrs = new HashMap<String, Object>();
@@ -1138,7 +1144,7 @@ public class ManifestParser
 
                 List<String> paths = new ArrayList();
                 paths.add((String)
-                    exports.get(i).getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR));
+                    exports.get(i).getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
                 clauseList.add(
                     new ParsedHeaderClause(
                         paths, Collections.EMPTY_MAP, attrs, Collections.EMPTY_MAP));
@@ -1252,7 +1258,7 @@ public class ManifestParser
             // Create a require capability and return it.
             String symName = (String) clauses.get(0).m_paths.get(0);
             Map<String, Object> attrs = new HashMap<String, Object>(2);
-            attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symName);
+            attrs.put(BundleRevision.BUNDLE_NAMESPACE, symName);
             attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersion);
             return new BundleCapabilityImpl(
                 owner,
@@ -1317,7 +1323,7 @@ public class ManifestParser
                 Map<String, Object> attrs = clauses.get(0).m_attrs;
                 Map<String, Object> newAttrs = new HashMap<String, Object>(attrs.size() + 1);
                 newAttrs.put(
-                    Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE,
+                    BundleRevision.HOST_NAMESPACE,
                     clauses.get(0).m_paths.get(0));
                 newAttrs.putAll(attrs);
 
@@ -1403,7 +1409,7 @@ public class ManifestParser
                 // Prepend the symbolic name to the array of attributes.
                 Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
                 newAttrs.put(
-                    Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE,
+                    BundleRevision.BUNDLE_NAMESPACE,
                     path);
                 newAttrs.putAll(attrs);
 

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java?rev=1136150&r1=1136149&r2=1136150&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java Wed Jun 15 18:57:20 2011
@@ -36,7 +36,6 @@ public class BundleCapabilityImpl implem
 {
     public static final String SINGLETON_NAMESPACE = "singleton";
 
-    public static final String PACKAGE_ATTR = "package";
     public static final String VERSION_ATTR = "version";
 
     private final BundleRevision m_revision;
@@ -199,7 +198,7 @@ public class BundleCapabilityImpl implem
         if (m_namespace.equals(BundleRevision.PACKAGE_NAMESPACE))
         {
             return "[" + m_revision + "] "
-                + m_namespace + "; " + m_attrs.get(PACKAGE_ATTR);
+                + m_namespace + "; " + m_attrs.get(BundleRevision.PACKAGE_NAMESPACE);
         }
         return "[" + m_revision + "] " + m_namespace + "; " + m_attrs;
     }