When populating candidates, we need to check for a failed result
after recursing since cycles may cause the resolving revision to
fail in a deeper recursion. We weren't checking this previously,
which caused us to ignore failures in some cases. (FELIX-3178)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1203866 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java b/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
index a411bcb..d244685 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/Candidates.java
@@ -257,7 +257,7 @@
         }
 
         // If we have requirements remaining, then find candidates for them.
-        while (remainingReqs.size() > 0)
+        while (!remainingReqs.isEmpty())
         {
             BundleRequirement req = remainingReqs.remove(0);
 
@@ -276,10 +276,16 @@
                 state.getCandidates((BundleRequirementImpl) req, true);
             ResolveException rethrow = processCandidates(state, revision, candidates);
 
-            // If there are no candidates for the current requirement
-            // and it is not optional, then create, cache, and throw
-            // a resolve exception.
-            if (candidates.isEmpty() && !((BundleRequirementImpl) req).isOptional())
+            // First, due to cycles, makes sure we haven't already failed in
+            // a deeper recursion.
+            Object result = m_populateResultCache.get(revision);
+            if (result instanceof ResolveException)
+            {
+                throw (ResolveException) result;
+            }
+            // Next, if are no candidates remaining and the requirement is not
+            // not optional, then record and throw a resolve exception.
+            else if (candidates.isEmpty() && !((BundleRequirementImpl) req).isOptional())
             {
                 String msg = "Unable to resolve " + revision
                     + ": missing requirement " + req;
@@ -291,7 +297,7 @@
                 m_populateResultCache.put(revision, rethrow);
                 throw rethrow;
             }
-            // If we actually have candidates for the requirement, then
+            // Otherwise, if we actually have candidates for the requirement, then
             // add them to the local candidate map.
             else if (candidates.size() > 0)
             {
@@ -455,9 +461,8 @@
             // since we effectively chain exception messages for each level
             // of recursion; thus, any avoided recursion results in fewer
             // exceptions to chain when an error does occur.
-            if (isFragment
-                || ((candCap.getRevision().getWiring() == null)
-                    && !candCap.getRevision().equals(revision)))
+            if ((isFragment || (candCap.getRevision().getWiring() == null))
+                && !candCap.getRevision().equals(revision))
             {
                 try
                 {
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
index 6b2772e..20c31ff 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
@@ -229,11 +229,11 @@
 
         // Combine all requirements.
         m_requirements = new ArrayList(
-            importReqs.size() + rbReqs.size() + hostReqs.size()
+            hostReqs.size() + importReqs.size() + rbReqs.size()
             + requireReqs.size() + dynamicReqs.size());
+        m_requirements.addAll(hostReqs);
         m_requirements.addAll(importReqs);
         m_requirements.addAll(rbReqs);
-        m_requirements.addAll(hostReqs);
         m_requirements.addAll(requireReqs);
         m_requirements.addAll(dynamicReqs);