Factor out some duplicate code. (FELIX-2986)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1166251 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index 6f85a59..dbab9a7 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -152,90 +152,9 @@
                 }
             }
 
-            // Get resolver hook factories.
+            // Prepare resolver hooks, if any.
             Set<ServiceReference<ResolverHookFactory>> hookRefs =
-                m_felix.getHooks(ResolverHookFactory.class);
-            if (!hookRefs.isEmpty())
-            {
-                // Create triggers list.
-                Set<BundleRevision> triggers;
-                if (!mandatoryRevisions.isEmpty() && !optionalRevisions.isEmpty())
-                {
-                    triggers = new HashSet<BundleRevision>(mandatoryRevisions);
-                    triggers.addAll(optionalRevisions);
-                }
-                else
-                {
-                    triggers = (mandatoryRevisions.isEmpty())
-                        ? optionalRevisions : mandatoryRevisions;
-                }
-                triggers = Collections.unmodifiableSet(triggers);
-
-                // Create resolver hook objects by calling begin() on factory.
-                for (ServiceReference<ResolverHookFactory> ref : hookRefs)
-                {
-                    try
-                    {
-                        ResolverHookFactory rhf = m_felix.getService(m_felix, ref);
-                        if (rhf != null)
-                        {
-                            ResolverHook hook =
-                                Felix.m_secureAction
-                                    .invokeResolverHookFactory(rhf, triggers);
-                            if (hook != null)
-                            {
-                                m_hooks.add(hook);
-                            }
-                        }
-                    }
-                    catch (Throwable ex)
-                    {
-                        throw new BundleException(
-                            "Resolver hook exception: " + ex.getMessage(),
-                            BundleException.REJECTED_BY_HOOK,
-                            ex);
-                    }
-                }
-
-                // Ask hooks to indicate which revisions should not be resolved.
-                m_whitelist =
-                    new ShrinkableCollection<BundleRevision>(
-                        m_resolverState.getUnresolvedRevisions());
-                int originalSize = m_whitelist.size();
-                for (ResolverHook hook : m_hooks)
-                {
-                    try
-                    {
-                        Felix.m_secureAction
-                            .invokeResolverHookResolvable(hook, m_whitelist);
-                    }
-                    catch (Throwable ex)
-                    {
-                        throw new BundleException(
-                            "Resolver hook exception: " + ex.getMessage(),
-                            BundleException.REJECTED_BY_HOOK,
-                            ex);
-                    }
-                }
-                // If nothing was removed, then just null the whitelist
-                // as an optimization.
-                if (m_whitelist.size() == originalSize)
-                {
-                    m_whitelist = null;
-                }
-
-                // Check to make sure the target revision is allowed to resolve.
-                if (m_whitelist != null)
-                {
-                    mandatoryRevisions.retainAll(m_whitelist);
-                    optionalRevisions.retainAll(m_whitelist);
-                    if (mandatoryRevisions.isEmpty() && optionalRevisions.isEmpty())
-                    {
-                        throw new ResolveException(
-                            "Resolver hook prevented resolution.", null, null);
-                    }
-                }
-            }
+                prepareResolverHooks(mandatoryRevisions, optionalRevisions);
 
             // Catch any resolve exception to rethrow later because
             // we may need to call end() on resolver hooks.
@@ -254,44 +173,8 @@
                 rethrow = ex;
             }
 
-            // If we have resolver hooks, we must call end() on them.
-            if (!hookRefs.isEmpty())
-            {
-                // Verify that all resolver hook service references are still valid
-                // Call end() on resolver hooks.
-                for (ResolverHook hook : m_hooks)
-                {
-// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
-//       to their svc ref since we aren't supposed to call end() on unregistered
-//       but currently we call end() on all.
-                    try
-                    {
-                        Felix.m_secureAction.invokeResolverHookEnd(hook);
-                    }
-                    catch (Throwable th)
-                    {
-                        m_logger.log(
-                            Logger.LOG_WARNING, "Resolver hook exception.", th);
-                    }
-                }
-                // Verify that all hook service references are still valid
-                // and unget all resolver hook factories.
-                boolean invalid = false;
-                for (ServiceReference<ResolverHookFactory> ref : hookRefs)
-                {
-                    if (ref.getBundle() == null)
-                    {
-                        invalid = true;
-                    }
-                    m_felix.ungetService(m_felix, ref);
-                }
-                if (invalid)
-                {
-                    throw new BundleException(
-                        "Resolver hook service unregistered during resolve.",
-                        BundleException.REJECTED_BY_HOOK);
-                }
-            }
+            // Release resolver hooks, if any.
+            releaseResolverHooks(hookRefs);
 
             // If the resolve failed, rethrow the exception.
             if (rethrow != null)
@@ -357,73 +240,10 @@
                     .getImportedPackageSource(pkgName);
                 if (provider == null)
                 {
-                    // Get resolver hook factories.
+                    // Prepare resolver hooks, if any.
                     Set<ServiceReference<ResolverHookFactory>> hookRefs =
-                        m_felix.getHooks(ResolverHookFactory.class);
-                    if (!hookRefs.isEmpty())
-                    {
-                        // Create triggers list.
-                        List<BundleRevision> triggers = new ArrayList<BundleRevision>(1);
-                        triggers.add(revision);
-                        triggers = Collections.unmodifiableList(triggers);
-
-                        // Create resolver hook objects by calling begin() on factory.
-                        for (ServiceReference<ResolverHookFactory> ref : hookRefs)
-                        {
-                            try
-                            {
-                                ResolverHookFactory rhf = m_felix.getService(m_felix, ref);
-                                if (rhf != null)
-                                {
-                                    ResolverHook hook =
-                                        Felix.m_secureAction
-                                            .invokeResolverHookFactory(rhf, triggers);
-                                    if (hook != null)
-                                    {
-                                        m_hooks.add(hook);
-                                    }
-                                }
-                            }
-                            catch (Throwable ex)
-                            {
-                                throw new BundleException(
-                                    "Resolver hook exception: " + ex.getMessage(),
-                                    BundleException.REJECTED_BY_HOOK,
-                                    ex);
-                            }
-                        }
-
-                        // Ask hooks to indicate which revisions should not be resolved.
-                        m_whitelist =
-                            new ShrinkableCollection<BundleRevision>(
-                                m_resolverState.getUnresolvedRevisions());
-                        int originalSize = m_whitelist.size();
-                        for (ResolverHook hook : m_hooks)
-                        {
-                            try
-                            {
-                                Felix.m_secureAction
-                                    .invokeResolverHookResolvable(hook, m_whitelist);
-                            }
-                            catch (Throwable ex)
-                            {
-                                throw new BundleException(
-                                    "Resolver hook exception: " + ex.getMessage(),
-                                    BundleException.REJECTED_BY_HOOK,
-                                    ex);
-                            }
-                        }
-                        // If nothing was removed, then just null the whitelist
-                        // as an optimization.
-                        if (m_whitelist.size() == originalSize)
-                        {
-                            m_whitelist = null;
-                        }
-
-                        // Since this is a dynamic import, the root revision is
-                        // already resolved, so we don't need to check it against
-                        // the whitelist as we do in other cases.
-                    }
+                        prepareResolverHooks(
+                            Collections.singleton(revision), Collections.EMPTY_SET);
 
                     // Catch any resolve exception to rethrow later because
                     // we may need to call end() on resolver hooks.
@@ -439,44 +259,8 @@
                         rethrow = ex;
                     }
 
-                    // If we have resolver hooks, we must call end() on them.
-                    if (!hookRefs.isEmpty())
-                    {
-                        // Verify that all resolver hook service references are still valid
-                        // Call end() on resolver hooks.
-                        for (ResolverHook hook : m_hooks)
-                        {
-// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
-//       to their svc ref since we aren't supposed to call end() on unregistered
-//       but currently we call end() on all.
-                            try
-                            {
-                                Felix.m_secureAction.invokeResolverHookEnd(hook);
-                            }
-                            catch (Throwable th)
-                            {
-                                m_logger.log(
-                                    Logger.LOG_WARNING, "Resolver hook exception.", th);
-                            }
-                        }
-                        // Verify that all hook service references are still valid
-                        // and unget all resolver hook factories.
-                        boolean invalid = false;
-                        for (ServiceReference<ResolverHookFactory> ref : hookRefs)
-                        {
-                            if (ref.getBundle() == null)
-                            {
-                                invalid = true;
-                            }
-                            m_felix.ungetService(m_felix, ref);
-                        }
-                        if (invalid)
-                        {
-                            throw new BundleException(
-                                "Resolver hook service unregistered during resolve.",
-                                BundleException.REJECTED_BY_HOOK);
-                        }
-                    }
+                    // Release resolver hooks, if any.
+                    releaseResolverHooks(hookRefs);
 
                     // If the resolve failed, rethrow the exception.
                     if (rethrow != null)
@@ -533,6 +317,153 @@
         return provider;
     }
 
+    private Set<ServiceReference<ResolverHookFactory>> prepareResolverHooks(
+        Set<BundleRevision> mandatory, Set<BundleRevision> optional)
+        throws BundleException
+    {
+        // Get resolver hook factories.
+        Set<ServiceReference<ResolverHookFactory>> hookRefs =
+            m_felix.getHooks(ResolverHookFactory.class);
+        if (!hookRefs.isEmpty())
+        {
+            // Create triggers list.
+            Set<BundleRevision> triggers;
+            if (!mandatory.isEmpty() && !optional.isEmpty())
+            {
+                triggers = new HashSet<BundleRevision>(mandatory);
+                triggers.addAll(optional);
+            }
+            else
+            {
+                triggers = (mandatory.isEmpty())
+                    ? optional : mandatory;
+            }
+            triggers = Collections.unmodifiableSet(triggers);
+
+            // Create resolver hook objects by calling begin() on factory.
+            for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+            {
+                try
+                {
+                    ResolverHookFactory rhf = m_felix.getService(m_felix, ref);
+                    if (rhf != null)
+                    {
+                        ResolverHook hook =
+                            Felix.m_secureAction
+                                .invokeResolverHookFactory(rhf, triggers);
+                        if (hook != null)
+                        {
+                            m_hooks.add(hook);
+                        }
+                    }
+                }
+                catch (Throwable ex)
+                {
+                    throw new BundleException(
+                        "Resolver hook exception: " + ex.getMessage(),
+                        BundleException.REJECTED_BY_HOOK,
+                        ex);
+                }
+            }
+
+            // Ask hooks to indicate which revisions should not be resolved.
+            m_whitelist =
+                new ShrinkableCollection<BundleRevision>(
+                    m_resolverState.getUnresolvedRevisions());
+            int originalSize = m_whitelist.size();
+            for (ResolverHook hook : m_hooks)
+            {
+                try
+                {
+                    Felix.m_secureAction
+                        .invokeResolverHookResolvable(hook, m_whitelist);
+                }
+                catch (Throwable ex)
+                {
+                    throw new BundleException(
+                        "Resolver hook exception: " + ex.getMessage(),
+                        BundleException.REJECTED_BY_HOOK,
+                        ex);
+                }
+            }
+            // If nothing was removed, then just null the whitelist
+            // as an optimization.
+            if (m_whitelist.size() == originalSize)
+            {
+                m_whitelist = null;
+            }
+
+            // Check to make sure the target revisions are allowed to resolve.
+            if (m_whitelist != null)
+            {
+                // We only need to check this for the non-dynamic import
+                // case. The dynamic import case will only have one resolved
+                // trigger revision in the mandatory set, so ignore that case.
+                if (mandatory.isEmpty()
+                    || !optional.isEmpty()
+                    || (mandatory.iterator().next().getWiring() == null))
+                {
+                    mandatory.retainAll(m_whitelist);
+                    optional.retainAll(m_whitelist);
+                    if (mandatory.isEmpty() && optional.isEmpty())
+                    {
+                        throw new ResolveException(
+                            "Resolver hook prevented resolution.", null, null);
+                    }
+                }
+            }
+        }
+        else
+        {
+            m_hooks.clear();
+        }
+
+        return hookRefs;
+    }
+
+    private void releaseResolverHooks(Set<ServiceReference<ResolverHookFactory>> hookRefs)
+        throws BundleException
+    {
+        // If we have resolver hooks, we must call end() on them.
+        if (!hookRefs.isEmpty())
+        {
+            // Verify that all resolver hook service references are still valid
+            // Call end() on resolver hooks.
+            for (ResolverHook hook : m_hooks)
+            {
+// TODO: OSGi R4.3/RESOLVER HOOK - We likely need to put these hooks into a map
+//       to their svc ref since we aren't supposed to call end() on unregistered
+//       but currently we call end() on all.
+                try
+                {
+                    Felix.m_secureAction.invokeResolverHookEnd(hook);
+                }
+                catch (Throwable th)
+                {
+                    m_logger.log(
+                        Logger.LOG_WARNING, "Resolver hook exception.", th);
+                }
+            }
+            // Verify that all hook service references are still valid
+            // and unget all resolver hook factories.
+            boolean invalid = false;
+            for (ServiceReference<ResolverHookFactory> ref : hookRefs)
+            {
+                if (ref.getBundle() == null)
+                {
+                    invalid = true;
+                }
+                m_felix.ungetService(m_felix, ref);
+            }
+            if (invalid)
+            {
+                throw new BundleException(
+                    "Resolver hook service unregistered during resolve.",
+                    BundleException.REJECTED_BY_HOOK);
+            }
+        }
+    }
+
     // This method duplicates a lot of logic from:
     // ResolverImpl.getDynamicImportCandidates()
     boolean isAllowedDynamicImport(BundleRevision revision, String pkgName)