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 2010/01/28 23:25:37 UTC

svn commit: r904281 - in /felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework: Felix.java resolver/ResolverImpl.java

Author: rickhall
Date: Thu Jan 28 22:25:36 2010
New Revision: 904281

URL: http://svn.apache.org/viewvc?rev=904281&view=rev
Log:
Fix more issues with dynamic imports.

Modified:
    felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java
    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/Felix.java
URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java?rev=904281&r1=904280&r2=904281&view=diff
==============================================================================
--- felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/sandbox/rickhall/framework-proto/src/main/java/org/apache/felix/framework/Felix.java Thu Jan 28 22:25:36 2010
@@ -2504,7 +2504,6 @@
                             "Could not remove from cache.", ex1);
                     }
                 }
-
                 if (ex instanceof BundleException)
                 {
                     throw (BundleException) ex;
@@ -3916,7 +3915,7 @@
             // okay since the resolver will double check later after we have
             // acquired the global lock below.
             if (module.isResolved()
-                && (ResolverImpl.findAllowedDynamicImport(m_resolverState, module, pkgName) != null))
+                && (ResolverImpl.isAllowedDynamicImport(m_resolverState, module, pkgName, new HashMap())))
             {
                 // Acquire global lock.
                 boolean locked = acquireGlobalLock();

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=904281&r1=904280&r2=904281&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 Thu Jan 28 22:25:36 2010
@@ -87,7 +87,7 @@
         {
             m_candidatePermutations.clear();
 
-System.out.println("+++ RESOLVING " + module);
+//System.out.println("+++ RESOLVING " + module);
             Map<Requirement, Set<Capability>> candidateMap =
                 new HashMap<Requirement, Set<Capability>>();
 
@@ -101,7 +101,7 @@
                 rethrow = null;
 
                 candidateMap = m_candidatePermutations.remove(0);
-dumpCandidateMap(state, candidateMap);
+//dumpCandidateMap(state, candidateMap);
 
                 try
                 {
@@ -152,18 +152,16 @@
         // 5. The package in question matches a dynamic import of the bundle.
         // The following call checks all of these conditions and returns
         // a matching dynamic requirement if possible.
-        Requirement dynReq = findAllowedDynamicImport(state, module, pkgName);
-        if (dynReq != null)
+        Map<Requirement, Set<Capability>> candidateMap =
+            new HashMap<Requirement, Set<Capability>>();
+        if (isAllowedDynamicImport(state, module, pkgName, candidateMap))
         {
             m_candidatePermutations.clear();
 
             Map<Module, Packages> modulePkgMap = new HashMap<Module, Packages>();
 
-System.out.println("+++ DYNAMICALLY RESOLVING " + module + " - " + dynReq);
-            Map<Requirement, Set<Capability>> candidateMap =
-                new HashMap<Requirement, Set<Capability>>();
-
-            populateDynamicCandidates(state, module, dynReq, candidateMap, new HashSet<Module>());
+//System.out.println("+++ DYNAMICALLY RESOLVING " + module + " - " + pkgName);
+            populateDynamicCandidates(state, module, candidateMap, new HashSet<Module>());
             m_candidatePermutations.add(candidateMap);
             ResolveException rethrow = null;
 
@@ -172,7 +170,7 @@
                 rethrow = null;
 
                 candidateMap = m_candidatePermutations.remove(0);
-dumpCandidateMap(state, candidateMap);
+//dumpCandidateMap(state, candidateMap);
 
                 try
                 {
@@ -201,21 +199,26 @@
                 populateDynamicWireMap(
                     module, pkgName, modulePkgMap, new HashMap<Module, List<Wire>>());
 
+//System.out.println("+++ DYNAMIC SUCCESS: " + wireMap.get(module));
             return wireMap;
         }
 
+//System.out.println("+++ DYNAMIC FAILURE");
         return null;
     }
 
     // TODO: FELIX3 - It would be nice to make this private.
-    public static Requirement findAllowedDynamicImport(
-        ResolverState state, Module module, String pkgName)
+    // TODO: FELIX3 - At a minimum, figure out a different way than passing in the
+    //       candidate map.
+    public static boolean isAllowedDynamicImport(
+        ResolverState state, Module module, String pkgName, Map<Requirement,
+        Set<Capability>> candidateMap)
     {
         // Unresolved modules cannot dynamically import, nor can the default
         // package be dynamically imported.
         if (!module.isResolved() || pkgName.length() == 0)
         {
-            return null;
+            return false;
         }
 
         // If any of the module exports this package, then we cannot
@@ -226,7 +229,7 @@
             if (caps.get(i).getNamespace().equals(Capability.PACKAGE_NAMESPACE)
                 && caps.get(i).getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName))
             {
-                return null;
+                return false;
             }
         }
         // If any of our wires have this package, then we cannot
@@ -236,7 +239,7 @@
         {
             if (wires.get(i).hasPackage(pkgName))
             {
-                return null;
+                return false;
             }
         }
 
@@ -249,20 +252,48 @@
         Requirement req = new RequirementImpl(Capability.PACKAGE_NAMESPACE, dirs, attrs);
         Set<Capability> candidates = state.getCandidates(module, req, false);
         List<Requirement> dynamics = module.getDynamicRequirements();
+
+        // First find a dynamic requirement that matches the capabilities.
+        Requirement dynReq = null;
         for (int dynIdx = 0;
-            (candidates.size() > 0) && (dynIdx < dynamics.size());
+            (candidates.size() > 0) && (dynReq == null) && (dynIdx < dynamics.size());
             dynIdx++)
         {
-            for (Capability cap : candidates)
+            for (Iterator<Capability> itCand = candidates.iterator();
+                (dynReq == null) && itCand.hasNext(); )
             {
+                Capability cap = itCand.next();
                 if (CapabilitySet.matches(cap, dynamics.get(dynIdx).getFilter()))
                 {
-                    return dynamics.get(dynIdx);
+                    dynReq = dynamics.get(dynIdx);
                 }
             }
         }
 
-        return null;
+        // If we found a matching dynamic requirement, then filter out
+        // any candidates that do not match it.
+        if (dynReq != null)
+        {
+            for (Iterator<Capability> itCand = candidates.iterator(); itCand.hasNext(); )
+            {
+                Capability cap = itCand.next();
+                if (!CapabilitySet.matches(cap, dynReq.getFilter()))
+                {
+                    itCand.remove();
+                }
+            }
+            
+            if (candidates.size() > 0)
+            {
+                candidateMap.put(dynReq, candidates);
+            }
+        }
+        else
+        {
+            candidates.clear();
+        }
+
+        return !candidates.isEmpty();
     }
 
     private static void dumpCandidateMap(
@@ -390,7 +421,7 @@
     }
 
     private static void populateDynamicCandidates(
-        ResolverState state, Module module, Requirement dynReq,
+        ResolverState state, Module module,
         Map<Requirement, Set<Capability>> candidateMap, Set<Module> cycles)
     {
         if (m_isInvokeCount)
@@ -408,8 +439,12 @@
         }
         cycles.add(module);
 
-        // Find candidates for all requirements for the target module.
-        Set<Capability> candidates = state.getCandidates(module, dynReq, true);
+        // 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.
+        Entry<Requirement, Set<Capability>> entry = candidateMap.entrySet().iterator().next();
+        Requirement dynReq = entry.getKey();
+        Set<Capability> candidates = entry.getValue();
         for (Iterator<Capability> itCandCap = candidates.iterator(); itCandCap.hasNext(); )
         {
             Capability candCap = itCandCap.next();
@@ -427,18 +462,21 @@
             }
         }
 
-        // Put candidates for all requirements into the global candidate map.
-        if (candidates.size() > 0)
+// TODO: FELIX3 - Since we reuse the same dynamic requirement, it is possible
+//       that some sort of cycle could cause us to try try to match another
+//       set of candidates to the same requirement.
+        if (candidates.size() == 0)
         {
-            candidateMap.put(dynReq, candidates);
+            candidateMap.remove(dynReq);
+            throw new ResolveException("Dynamic import failed.", module, dynReq);
+        }
 
-            // Add existing wires as candidates.
-            for (Wire wire : module.getWires())
-            {
-                Set<Capability> cs = new TreeSet();
-                cs.add(wire.getCapability());
-                candidateMap.put(wire.getRequirement(), cs);
-            }
+        // Add existing wires as candidates.
+        for (Wire wire : module.getWires())
+        {
+            Set<Capability> cs = new TreeSet();
+            cs.add(wire.getCapability());
+            candidateMap.put(wire.getRequirement(), cs);
         }
     }
 
@@ -513,7 +551,7 @@
                 for (Iterator<Capability> it = candCaps.iterator(); it.hasNext(); )
                 {
                     Capability candCap = it.next();
-System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
+//System.out.println("+++ TRYING CAND " + candCap + " FOR " + req);
                     try
                     {
                         // Try to resolve the candidate.
@@ -666,7 +704,7 @@
 //       then it should be listed as an export.
         if (candBlame.m_cap.getNamespace().equals(Capability.PACKAGE_NAMESPACE))
         {
-System.out.println("+++ MERGING " + candBlame.m_cap + " INTO " + current);
+//System.out.println("+++ MERGING " + candBlame.m_cap + " INTO " + current);
             String pkgName = (String)
                 candBlame.m_cap.getAttribute(Capability.PACKAGE_ATTR).getValue();
 
@@ -757,7 +795,7 @@
                 currentPkgs.m_requiredPkgs.putAll(currentPkgsCopy.m_requiredPkgs);
                 currentPkgs.m_usedPkgs.putAll(currentPkgsCopy.m_usedPkgs);
             }
-dumpModulePkgs(current, currentPkgs);
+//dumpModulePkgs(current, currentPkgs);
         }
     }
 
@@ -844,10 +882,10 @@
                 List<Blame> currentRequiredBlames = currentPkgs.m_requiredPkgs.get(usedPkgName);
 
                 Packages candSourcePkgs = modulePkgMap.get(candSourceCap.getModule());
-System.out.println("+++ candSourceCap " + candSourceCap);
-System.out.println("+++ candSourceCap.getModule() " + candSourceCap.getModule() + " (" + candSourceCap.getModule().isResolved() + ")");
-System.out.println("+++ candSourcePkgs " + candSourcePkgs);
-System.out.println("+++ candSourcePkgs.m_exportedPkgs " + candSourcePkgs.m_exportedPkgs);
+//System.out.println("+++ candSourceCap " + candSourceCap);
+//System.out.println("+++ candSourceCap.getModule() " + candSourceCap.getModule() + " (" + candSourceCap.getModule().isResolved() + ")");
+//System.out.println("+++ candSourcePkgs " + candSourcePkgs);
+//System.out.println("+++ candSourcePkgs.m_exportedPkgs " + candSourcePkgs.m_exportedPkgs);
                 Blame candSourceBlame = candSourcePkgs.m_exportedPkgs.get(usedPkgName);
                 candSourceBlame = (candSourceBlame != null)
                     ? candSourceBlame
@@ -876,7 +914,7 @@
                         usedCaps = new ArrayList<Blame>();
                         currentPkgs.m_usedPkgs.put(usedPkgName, usedCaps);
                     }
-System.out.println("+++ MERGING CB " + candBlame + " SB " + candSourceBlame);
+//System.out.println("+++ MERGING CB " + candBlame + " SB " + candSourceBlame);
 //                    usedCaps.add(new Blame(candBlame.m_reqs, sourceBlame.m_cap));
                     usedCaps.add(candSourceBlame);
 //                    return;
@@ -1109,10 +1147,15 @@
                 && entry.getValue().m_cap.getAttribute(
                     Capability.PACKAGE_ATTR).getValue().equals(pkgName))
             {
+                List<Attribute> attrs = new ArrayList();
+                attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false));
                 packageWires.add(
                     new WireImpl(
                         module,
-                        entry.getValue().m_reqs.get(0),
+                        // We need an unique requirement here or else subsequent
+                        // dynamic imports for the same dynamic requirement will
+                        // conflict with previous ones.
+                        new RequirementImpl(Capability.PACKAGE_NAMESPACE, new ArrayList(0), attrs),
                         entry.getValue().m_cap.getModule(),
                         entry.getValue().m_cap));
             }