Resolved a concurrency issue that could result in the same bundle being
resolved more than once; also tried to simplify locking in the core search
policy implementation. (FELIX-381)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@580747 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index ece37b5..2fa49af 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -623,8 +623,17 @@
                             acquireBundleLock(bundle);
                             if (bundle.getInfo().getCurrentModule() == event.getModule())
                             {
-                                bundle.getInfo().setState(Bundle.RESOLVED);
-                                fireBundleEvent(BundleEvent.RESOLVED, bundle);
+                                if (bundle.getInfo().getState() != Bundle.INSTALLED)
+                                {
+                                    m_logger.log(
+                                        Logger.LOG_WARNING,
+                                        "Received a resolve event for a bundle that has already been resolved.");
+                                }
+                                else
+                                {
+                                    bundle.getInfo().setState(Bundle.RESOLVED);
+                                    fireBundleEvent(BundleEvent.RESOLVED, bundle);
+                                }
                             }
                         }
                         finally
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
index 581edce..fbaa569 100755
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -125,13 +125,23 @@
         }
     }
 
-    protected synchronized boolean isResolved(IModule module)
+    /**
+     * Private utility method to check module resolved state.
+     * CONCURRENCY NOTE: This method must be called while holding
+     * a lock on m_factory.
+    **/
+    private boolean isResolved(IModule module)
     {
         ModuleData data = (ModuleData) m_moduleDataMap.get(module);
         return (data == null) ? false : data.m_resolved;
     }
 
-    protected synchronized void setResolved(IModule module, boolean resolved)
+    /**
+     * Private utility method to set module resolved state.
+     * CONCURRENCY NOTE: This method must be called while holding
+     * a lock on m_factory.
+    **/
+    private void setResolved(IModule module, boolean resolved)
     {
         ModuleData data = (ModuleData) m_moduleDataMap.get(module);
         if (data == null)
@@ -904,19 +914,6 @@
     public void resolve(IModule rootModule)
         throws ResolveException
     {
-        // If the module is already resolved, then we can just return.
-        if (isResolved(rootModule))
-        {
-            return;
-        }
-
-        // This variable maps an unresolved module to a list of candidate
-        // sets, where there is one candidate set for each requirement that
-        // must be resolved. A candidate set contains the potential canidates
-        // available to resolve the requirement and the currently selected
-        // candidate index.
-        Map candidatesMap = new HashMap();
-
         // This map will be used to hold the final wires for all
         // resolved modules, which can then be used to fire resolved
         // events outside of the synchronized block.
@@ -927,6 +924,19 @@
         // middle of this operation.
         synchronized (m_factory)
         {
+            // If the module is already resolved, then we can just return.
+            if (isResolved(rootModule))
+            {
+                return;
+            }
+
+            // This variable maps an unresolved module to a list of candidate
+            // sets, where there is one candidate set for each requirement that
+            // must be resolved. A candidate set contains the potential canidates
+            // available to resolve the requirement and the currently selected
+            // candidate index.
+            Map candidatesMap = new HashMap();
+
             // The first step is to populate the candidates map. This
             // will use the target module to populate the candidates map
             // with all potential modules that need to be resolved as a