felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickh...@apache.org
Subject svn commit: r909287 - /felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
Date Fri, 12 Feb 2010 08:22:16 GMT
Author: rickhall
Date: Fri Feb 12 08:22:16 2010
New Revision: 909287

URL: http://svn.apache.org/viewvc?rev=909287&view=rev
Log:
Properly clean up after broken cycles.

Modified:
    felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java

Modified: felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java?rev=909287&r1=909286&r2=909287&view=diff
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
(original)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/resolver/ResolverImpl.java
Fri Feb 12 08:22:16 2010
@@ -94,8 +94,8 @@
             Map<Requirement, Set<Capability>> candidateMap =
                 new HashMap<Requirement, Set<Capability>>();
 
-            populateCandidates(state, module, candidateMap,
-                m_fwkExecEnvStr, m_fwkExecEnvSet, new HashMap<Module, ResolveException>());
+            populateCandidates(state, null, module, candidateMap,
+                m_fwkExecEnvStr, m_fwkExecEnvSet, new HashMap<Module, Object>());
             m_candidatePermutations.add(candidateMap);
 
             ResolveException rethrow = null;
@@ -166,7 +166,7 @@
 
 //System.out.println("+++ DYNAMICALLY RESOLVING " + module + " - " + pkgName);
             populateDynamicCandidates(state, module, candidateMap,
-                m_fwkExecEnvStr, m_fwkExecEnvSet, new HashMap<Module, ResolveException>());
+                m_fwkExecEnvStr, m_fwkExecEnvSet);
             m_candidatePermutations.add(candidateMap);
             ResolveException rethrow = null;
 
@@ -364,9 +364,9 @@
     }
 
     private static void populateCandidates(
-        ResolverState state, Module module,
+        ResolverState state, Module instigator, Module module,
         Map<Requirement, Set<Capability>> candidateMap,
-        String fwkExecEnvStr, Set fwkExecEnvSet, Map<Module, ResolveException> cycles)
+        String fwkExecEnvStr, Set fwkExecEnvSet, Map<Module, Object> resultCache)
     {
         if (m_isInvokeCount)
         {
@@ -376,16 +376,35 @@
             m_invokeCounts.put(methodName, count);
         }
 
-        // Detect cycles.
-        if (cycles.containsKey(module))
+        // Determine if we've already calculated this module's candidates.
+        // The result cache will have one of three values:
+        //   1. A resolve exception if there are not sufficient candidates
+        //      to resolve the module.
+        //   2. A list of modules involved in a cycle with this module, which
+        //      is used to clean up failed cycles; this value only exists while
+        //      candidates are being populated.
+        //   3. Boolean.TRUE indicating candidates for all requirements where
+        //      successfully calculated.
+        // For case 1, rethrow the exception. For case 2, record the current
+        // instigator module as being in a cycle with the target module and
+        // return immediately. For case 3, simply return immediately.
+        Object o = resultCache.get(module);
+        if (o instanceof ResolveException)
+        {
+            throw (ResolveException) o;
+        }
+        else if (o instanceof List)
         {
-            if (cycles.get(module) != null)
+            if (!((List) o).contains(instigator))
             {
-                throw cycles.get(module);
+                ((List) o).add(instigator);
             }
             return;
         }
-        cycles.put(module, null);
+        else if (o != null)
+        {
+            return;
+        }
 
         // Verify that any required execution environment is satisfied.
         verifyExecutionEnvironment(fwkExecEnvStr, fwkExecEnvSet, module);
@@ -393,6 +412,10 @@
         // Verify that any native libraries match the current platform.
         verifyNativeLibraries(module);
 
+        // Add this module to cache map so we know we are in the middle
+        // of calculating its candidates.
+        resultCache.put(module, new ArrayList());
+
         // Store candidates in a local map first, just in case the module
         // is not resolvable.
         Map<Requirement, Set<Capability>> localCandidateMap = new HashMap();
@@ -409,8 +432,8 @@
                 {
                     try
                     {
-                        populateCandidates(state, candCap.getModule(), candidateMap,
-                            fwkExecEnvStr, fwkExecEnvSet, cycles);
+                        populateCandidates(state, module, candCap.getModule(),
+                            candidateMap, fwkExecEnvStr, fwkExecEnvSet, resultCache);
                     }
                     catch (ResolveException ex)
                     {
@@ -421,10 +444,14 @@
             }
             if ((candidates.size() == 0) && !req.isOptional())
             {
+                // Remove invalid candidate and any cycle byproduct resolved modules.
+                removeInvalidCandidate(module, candidateMap, resultCache, new ArrayList());
+
                 ResolveException ex =
                     new ResolveException("Unable to resolve " + module
                         + ": missing requirement " + req, module, req);
-                cycles.put(module, ex);
+                resultCache.put(module, ex);
+
                 throw ex;
             }
             else if (candidates.size() > 0)
@@ -433,6 +460,8 @@
             }
         }
 
+        resultCache.put(module, Boolean.TRUE);
+
         // Put candidates for all requirements into the global candidate map.
         if (localCandidateMap.size() > 0)
         {
@@ -440,10 +469,83 @@
         }
     }
 
+    private static void removeInvalidCandidate(
+        Module invalidModule, Map<Requirement, Set<Capability>> candidatesMap,
+        Map<Module, Object> resultCache, List<Module> invalidModules)
+    {
+        // Remove the invalid module's candidates from the candidates map,
+        // since it should only contain entries for resolved modules.
+        for (Requirement req : invalidModule.getRequirements())
+        {
+            candidatesMap.remove(req);
+        }
+
+        // Remove the partial result from the result cache.
+        Object o = resultCache.remove(invalidModule);
+
+        // If the value in the result cache is a list, then there are modules
+        // in a cyclical relationship with the invalid module that need to
+        // be cleaned up.
+        if (o instanceof List)
+        {
+            // Loop through each cyclically dependent module.
+            List<Module> dependents = (List<Module>) o;
+            for (Module dep : dependents)
+            {
+                // Loop through its requirements to find any with the invalid
+                // module as a candidate.
+                for (Requirement req : dep.getRequirements())
+                {
+                    Set<Capability> cands = candidatesMap.get(req);
+                    if (cands != null)
+                    {
+                        for (Iterator<Capability> itCandCaps = cands.iterator();
+                            itCandCaps.hasNext(); )
+                        {
+                            // If the candidate capability is from the invalid module,
+                            // then remove it from the available candidates.
+                            if (itCandCaps.next().getModule().equals(invalidModule))
+                            {
+                                itCandCaps.remove();
+
+                                // If there are no more candidates available, then
+                                // remove it from the candidates map.
+                                if (cands.size() == 0)
+                                {
+                                    candidatesMap.remove(req);
+
+                                    // If the requirement is not optional, then record
+                                    // the dependent module as invalid.
+                                    if (!req.isOptional() && (dep != invalidModule)
+                                        && !invalidModules.contains(dep))
+                                    {
+                                        invalidModules.add(dep);
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // If more modules were invalidated, then recursively clean them
+        // up as well.
+        if (!invalidModules.isEmpty())
+        {
+            while (!invalidModules.isEmpty())
+            {
+                Module m = invalidModules.remove(0);
+                removeInvalidCandidate(m, candidatesMap, resultCache, invalidModules);
+            }
+        }
+    }
+
     private static void populateDynamicCandidates(
         ResolverState state, Module module,
         Map<Requirement, Set<Capability>> candidateMap,
-        String fwkExecEnvStr, Set fwkExecEnvSet, Map<Module, ResolveException> cycles)
+        String fwkExecEnvStr, Set fwkExecEnvSet)
     {
         if (m_isInvokeCount)
         {
@@ -453,18 +555,6 @@
             m_invokeCounts.put(methodName, count);
         }
 
-        // Detect cycles.
-        if (cycles.containsKey(module))
-        {
-            if (cycles.get(module) != null)
-            {
-                throw cycles.get(module);
-            }
-            return;
-        }
-        cycles.put(module, null);
-
-
         // 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.
@@ -478,8 +568,8 @@
             {
                 try
                 {
-                    populateCandidates(state, candCap.getModule(), candidateMap,
-                        fwkExecEnvStr, fwkExecEnvSet, cycles);
+                    populateCandidates(state, module, candCap.getModule(), candidateMap,
+                        fwkExecEnvStr, fwkExecEnvSet, new HashMap<Module, Object>());
                 }
                 catch (ResolveException ex)
                 {



Mime
View raw message