518488 ShutdownSorter does not take into account bundles with references to services provided by the same bundle

Signed-off-by: ootto <olaf@x100.de>
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ShutdownSorter.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ShutdownSorter.java
index 4c406be..28394c6 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ShutdownSorter.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ShutdownSorter.java
@@ -93,7 +93,11 @@
                         Bundle[] usingBundles = serviceReference.getUsingBundles();

 

 						if (!isEmpty(usingBundles)) {

-							usingBundles = stream(usingBundles).filter(unsortedManagedBundles::contains).collect(toList()).toArray(new Bundle[]{});

+							usingBundles =

+									stream(usingBundles)

+											.filter(b -> unsortedManagedBundles.contains(b) && !b.equals(bundle))

+											.collect(toList())

+											.toArray(new Bundle[]{});

 						}

 

                         if (!isEmpty(usingBundles)) {

diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/BlueprintShutdownSorterTest.java b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/BlueprintShutdownSorterTest.java
index 0b5380a..1c6e254 100644
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/BlueprintShutdownSorterTest.java
+++ b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/BlueprintShutdownSorterTest.java
@@ -7,7 +7,7 @@
  * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0

  * is available at http://www.opensource.org/licenses/apache2.0.php.

  * You may elect to redistribute this code under either of these licenses. 

- * 

+ *

  * Contributors:

  *   VMware Inc.

  *****************************************************************************/

@@ -15,98 +15,140 @@
 package org.eclipse.gemini.blueprint.extender.internal.dependencies;

 

 import java.util.ArrayList;

-import java.util.Arrays;

 import java.util.List;

-

 import junit.framework.TestCase;

-

 import org.eclipse.gemini.blueprint.extender.internal.DependencyMockBundle;

 import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ShutdownSorter;

 import org.osgi.framework.Bundle;

+import org.osgi.framework.BundleException;

+

+

+import static java.util.Arrays.asList;

+import static org.assertj.core.api.Assertions.assertThat;

 

 /**

  * @author Costin Leau

  */

 public class BlueprintShutdownSorterTest extends TestCase {

 

-	// see tck-1.dot

-	public void testCase1() throws Exception {

-		DependencyMockBundle a = new DependencyMockBundle("A");

-		DependencyMockBundle b = new DependencyMockBundle("B");

-		DependencyMockBundle c = new DependencyMockBundle("C");

-		DependencyMockBundle d = new DependencyMockBundle("D");

-		DependencyMockBundle e = new DependencyMockBundle("E");

+    /**

+     * <pre>

+     * digraph G{

+     *  A;

+     *  B -> C;

+     *  D -> E;

+     *  E -> D;

+     * }

+     * </pre>

+     * Expected order is C, A, B, E, D

+     */

+    public void testCase1() throws Exception {

+        DependencyMockBundle a = new DependencyMockBundle("A");

+        DependencyMockBundle b = new DependencyMockBundle("B");

+        DependencyMockBundle c = new DependencyMockBundle("C");

+        DependencyMockBundle d = new DependencyMockBundle("D");

+        DependencyMockBundle e = new DependencyMockBundle("E");

 

-		b.setDependentOn(c);

-		d.setDependentOn(e);

-		e.setDependentOn(d);

+        b.setDependentOn(c);

+        d.setDependentOn(e);

+        e.setDependentOn(d);

 

-		List<Bundle> order = getOrder(a, b, c, d, e);

-		System.out.println("Shutdown order is " + order);

-		assertOrder(new Bundle[] { c, a, b, e, d }, order);

-	}

+        List<Bundle> order = getOrder(a, b, c, d, e);

+        assertOrder(order, c, a, b, e, d);

+    }

 

-	// similar to tck 2 but with D publishes a service with a lower ranking and

-	// needs to be destroyed first

-	public void testCase2() throws Exception {

-		DependencyMockBundle a = new DependencyMockBundle("A");

-		DependencyMockBundle b = new DependencyMockBundle("B");

-		DependencyMockBundle c = new DependencyMockBundle("C");

-		DependencyMockBundle d = new DependencyMockBundle("D");

-		DependencyMockBundle e = new DependencyMockBundle("E");

+    /**

+     * similar to tck 2 but with D publishes a service with a lower ranking and

+     * needs to be destroyed first:

+     *

+     * <pre>

+     * digraph G{

+     *  A;

+     *  B -> C;

+     *  D -> E; (lower rank)

+     *  E -> D; (high rank)

+     * }

+     * </pre>

+     */

+    public void testCase2() throws Exception {

+        DependencyMockBundle a = new DependencyMockBundle("A");

+        DependencyMockBundle b = new DependencyMockBundle("B");

+        DependencyMockBundle c = new DependencyMockBundle("C");

+        DependencyMockBundle d = new DependencyMockBundle("D");

+        DependencyMockBundle e = new DependencyMockBundle("E");

 

-		b.setDependentOn(c);

-		d.setDependentOn(e, -13, 12);

-		e.setDependentOn(d, 0, 14);

+        b.setDependentOn(c);

+        d.setDependentOn(e, -13, 12);

+        e.setDependentOn(d, 0, 14);

 

-		List<Bundle> order = getOrder(a, b, c, d, e);

-		System.out.println("Shutdown order is " + order);

-		assertOrder(new Bundle[] { c, a, b, d, e }, order);

-	}

+        List<Bundle> order = getOrder(a, b, c, d, e);

+        assertOrder(order, c, a, b, d, e);

+    }

 

-	/**

-	 * If the service of a managed bundle are consumed by an unmanaged bundle,

-	 * that dependency should not affect the shutdown ordering as gemini blueprint is only responsible for

-	 * orderly shutting down the bundles it is managing.

-	 */

-	public void testUnmanagedBundlesAreIgnoredForShutdownOrdering() throws Exception {

-		DependencyMockBundle a = new DependencyMockBundle("A");

-		DependencyMockBundle b = new DependencyMockBundle("B");

-		DependencyMockBundle c = new DependencyMockBundle("C");

-		DependencyMockBundle d = new DependencyMockBundle("D");

-		DependencyMockBundle e = new DependencyMockBundle("E");

-		DependencyMockBundle unmanaged = new DependencyMockBundle("F");

+    /**

+     * If the service of a managed bundle are consumed by an unmanaged bundle,

+     * that dependency should not affect the shutdown ordering as gemini blueprint is only responsible for

+     * orderly shutting down the bundles it is managing.

+     */

+    public void testUnmanagedBundlesAreIgnoredForShutdownOrdering() throws Exception {

+        DependencyMockBundle a = new DependencyMockBundle("A");

+        DependencyMockBundle b = new DependencyMockBundle("B");

+        DependencyMockBundle c = new DependencyMockBundle("C");

+        DependencyMockBundle d = new DependencyMockBundle("D");

+        DependencyMockBundle e = new DependencyMockBundle("E");

+        DependencyMockBundle unmanaged = new DependencyMockBundle("F");

 

-		b.setDependentOn(c);

-		d.setDependentOn(e, -13, 12);

-		e.setDependentOn(d, 0, 14);

-		a.setDependentOn(unmanaged);

+        b.setDependentOn(c);

+        d.setDependentOn(e, -13, 12);

+        e.setDependentOn(d, 0, 14);

+        a.setDependentOn(unmanaged);

 

-		List<Bundle> order = getOrder(a, b, c, d, e);

-		System.out.println("Shutdown order is " + order);

-		assertOrder(new Bundle[] { c, a, b, d, e }, order);

-	}

+        List<Bundle> order = getOrder(a, b, c, d, e);

+        assertOrder(order, c, a, b, d, e);

+    }

+

+    /**

+     * If the service of a managed bundle are consumed by an unmanaged bundle,

+     * that dependency should not affect the shutdown ordering as gemini blueprint is only responsible for

+     * orderly shutting down the bundles it is managing.

+     */

+    public void testReferencesToSelfProvidedServicesAreIgnoredForShutdownOrdering() throws Exception {

+        DependencyMockBundle a = new DependencyMockBundle("A");

+        DependencyMockBundle b = new DependencyMockBundle("B");

+        DependencyMockBundle c = new DependencyMockBundle("C");

+        DependencyMockBundle d = new DependencyMockBundle("D");

+        DependencyMockBundle e = new DependencyMockBundle("E");

+

+        e.setDependentOn(d);

+        d.setDependentOn(c);

+        c.setDependentOn(b);

+        b.setDependentOn(a);

+

+        a.setDependentOn(a);

+        b.setDependentOn(b);

+

+        List<Bundle> order = getOrder(a, b, c, d, e);

+        assertOrder(order, a, b, c, d, e);

+    }

 

 

-	private void assertOrder(Bundle[] expected, List<Bundle> ordered) {

-		assertTrue("shutdown order is incorrect", Arrays.equals(expected, ordered.toArray()));

-	}

+    private void assertOrder(List<Bundle> ordered, Bundle... expected) {

+        assertThat(ordered)

+                .describedAs("The order %s does not match the expected order %s", ordered, expected)

+                .containsExactly(expected);

+    }

 

-	private List<Bundle> getOrder(Bundle... bundles) {

-		List<Bundle> list = new ArrayList<Bundle>(bundles.length);

-		list.addAll(Arrays.asList(bundles));

-		List<Bundle> result = new ArrayList<Bundle>();

+    private List<Bundle> getOrder(Bundle... bundles) throws BundleException {

+        List<Bundle> list = new ArrayList<>(bundles.length);

+        list.addAll(asList(bundles));

+        List<Bundle> result = new ArrayList<>();

 

-		while (!list.isEmpty()) {

-			result.addAll(ShutdownSorter.getBundles(list));

-			for (Bundle bundle : result) {

-				try {

-					bundle.stop();

-				} catch (Exception ex) {

-					throw new RuntimeException(ex);

-				}

-			}

-		}

-		return result;

-	}

+        while (!list.isEmpty()) {

+            result.addAll(ShutdownSorter.getBundles(list));

+            for (Bundle bundle : result) {

+                bundle.stop();

+            }

+        }

+        return result;

+    }

 }

diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/blueprint-tck-1.dot b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/blueprint-tck-1.dot
deleted file mode 100644
index 4c337a3..0000000
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/blueprint-tck-1.dot
+++ /dev/null
@@ -1,8 +0,0 @@
-digraph G{

-    A;

-    B -> C;

-    D -> E;

-    E -> D;

-}

-

-// order is C, A, B, E, D
\ No newline at end of file
diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/blueprint-tck-2.dot b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/blueprint-tck-2.dot
deleted file mode 100644
index c47d862..0000000
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/blueprint-tck-2.dot
+++ /dev/null
@@ -1,6 +0,0 @@
-digraph G{

- 	A;

-	B -> C;

-	D -> E; (lower rank)

-	E -> D; (high rank)

-}
\ No newline at end of file