Bug 414070 - Add tests to verify shutdown sort order
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/META-INF/MANIFEST.MF
index 756ea91..f6d1f2f 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/META-INF/MANIFEST.MF
@@ -5,7 +5,7 @@
 Bundle-Version: 1.0.0
 Bundle-Activator: chain.test.a.Activator
 Bundle-Localization: plugin
-Import-Package: org.eclipse.osgi.tests.bundles,
+Import-Package: org.eclipse.osgi.tests.bundles; resolution:="optional",
  org.osgi.framework;version="1.3.0",
  chain.test.b,
  chain.test.c
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/chain/test/a/Activator.java b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/chain/test/a/Activator.java
index 98f2da3..0f1dc77 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/chain/test/a/Activator.java
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.a/chain/test/a/Activator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,11 +16,19 @@
 public class Activator implements BundleActivator {
 
 	public void start(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 	public void stop(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 }
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/META-INF/MANIFEST.MF
index d8c70c4..73f5be5 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/META-INF/MANIFEST.MF
@@ -5,7 +5,7 @@
 Bundle-Version: 1.0.0
 Bundle-Activator: chain.test.b.Activator
 Bundle-Localization: plugin
-Import-Package: org.eclipse.osgi.tests.bundles,
+Import-Package: org.eclipse.osgi.tests.bundles; resolution:="optional",
  org.osgi.framework;version="1.3.0",
  chain.test.c,
  chain.test.d
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/chain/test/b/Activator.java b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/chain/test/b/Activator.java
index 366b33b..d495102 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/chain/test/b/Activator.java
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.b/chain/test/b/Activator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,11 +16,19 @@
 public class Activator implements BundleActivator {
 
 	public void start(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 	public void stop(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 }
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/META-INF/MANIFEST.MF
index ce19453..526c4ac 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/META-INF/MANIFEST.MF
@@ -6,7 +6,7 @@
 Bundle-Localization: plugin
 Bundle-Activator: chain.test.c.Activator
 Export-Package: chain.test.c
-Import-Package: org.eclipse.osgi.tests.bundles,
+Import-Package: org.eclipse.osgi.tests.bundles; resolution:="optional",
  org.osgi.framework;version="1.3.0",
  chain.test.d
 Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/chain/test/c/Activator.java b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/chain/test/c/Activator.java
index cc108ac..2333d1c 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/chain/test/c/Activator.java
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.c/chain/test/c/Activator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,11 +16,19 @@
 public class Activator implements BundleActivator {
 
 	public void start(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 	public void stop(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 }
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/META-INF/MANIFEST.MF
index a8ff5fb..ac31646 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/META-INF/MANIFEST.MF
@@ -6,6 +6,6 @@
 Bundle-Localization: plugin
 Bundle-Activator: chain.test.d.Activator
 Export-Package: chain.test.d
-Import-Package: org.eclipse.osgi.tests.bundles,
+Import-Package: org.eclipse.osgi.tests.bundles; resolution:="optional",
  org.osgi.framework;version="1.3.0"
 Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/chain/test/d/Activator.java b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/chain/test/d/Activator.java
index efe9996..a675fce 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/chain/test/d/Activator.java
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test.d/chain/test/d/Activator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,11 +16,19 @@
 public class Activator implements BundleActivator {
 
 	public void start(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STARTED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 	public void stop(BundleContext context) throws Exception {
-		AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		try {
+			AbstractBundleTests.simpleResults.addEvent(new BundleEvent(BundleEvent.STOPPED, context.getBundle()));
+		} catch (NoClassDefFoundError e) {
+			// ignore, this is optional
+		}
 	}
 
 }
diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test/META-INF/MANIFEST.MF
index 4dfa9ef..e8d2a25 100644
--- a/bundles/org.eclipse.osgi.tests/bundles_src/chain.test/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/bundles_src/chain.test/META-INF/MANIFEST.MF
@@ -6,7 +6,7 @@
 Bundle-Localization: plugin
 Import-Package: chain.test.a,
  chain.test.b,
- org.eclipse.osgi.tests.bundles,
+ org.eclipse.osgi.tests.bundles; resolution:="optional",
  org.osgi.framework;version="1.3.0"
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: chain.test.Activator
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
index 14a8137..8a077d5 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
@@ -1945,6 +1945,66 @@
 		}
 	}
 
+	public void testBug414070() throws BundleException, InstantiationException, IllegalAccessException, ClassNotFoundException {
+		File config = OSGiTestsActivator.getContext().getDataFile(getName()); //$NON-NLS-1$
+		Map<String, Object> configuration = new HashMap<String, Object>();
+		configuration.put(Constants.FRAMEWORK_STORAGE, config.getAbsolutePath());
+		Equinox equinox = new Equinox(configuration);
+		equinox.init();
+
+		BundleContext systemContext = equinox.getBundleContext();
+		Bundle systemBundle = systemContext.getBundle();
+
+		Bundle chainTest = systemContext.installBundle(installer.getBundleLocation("chain.test")); //$NON-NLS-1$
+
+		final Bundle chainTestD = systemContext.installBundle(installer.getBundleLocation("chain.test.d")); //$NON-NLS-1$
+		Bundle chainTestA = systemContext.installBundle(installer.getBundleLocation("chain.test.a")); //$NON-NLS-1$
+		Bundle chainTestB = systemContext.installBundle(installer.getBundleLocation("chain.test.b")); //$NON-NLS-1$
+		Bundle chainTestC = systemContext.installBundle(installer.getBundleLocation("chain.test.c")); //$NON-NLS-1$
+		systemContext.registerService(WeavingHook.class, new WeavingHook() {
+			public void weave(WovenClass wovenClass) {
+				if (!chainTestD.equals(wovenClass.getBundleWiring().getBundle()))
+					return;
+				if (!"chain.test.d.DMultipleChain1".equals(wovenClass.getClassName()))
+					return;
+				List dynamicImports = wovenClass.getDynamicImports();
+				dynamicImports.add("*");
+			}
+		}, null);
+
+		equinox.start();
+
+		chainTest.loadClass("chain.test.TestMultiChain").newInstance(); //$NON-NLS-1$
+		// force a dynamic wire to cause a cycle
+		chainTestD.loadClass("chain.test.a.AMultiChain1");
+
+		// make sure all bundles are active now
+		assertEquals("A is not active.", Bundle.ACTIVE, chainTestA.getState());
+		assertEquals("B is not active.", Bundle.ACTIVE, chainTestB.getState());
+		assertEquals("C is not active.", Bundle.ACTIVE, chainTestC.getState());
+		assertEquals("D is not active.", Bundle.ACTIVE, chainTestD.getState());
+		// record STOPPING order
+		final List<Bundle> stoppingOrder = new ArrayList<Bundle>();
+		systemContext.addBundleListener(new SynchronousBundleListener() {
+			@Override
+			public void bundleChanged(BundleEvent event) {
+				if (event.getType() == BundleEvent.STOPPING) {
+					stoppingOrder.add(event.getBundle());
+				}
+			}
+		});
+		equinox.stop();
+		try {
+			equinox.waitForStop(10000);
+		} catch (InterruptedException e) {
+			Thread.currentThread().interrupt();
+			fail("Unexpected interruption.", e);
+		}
+
+		List<Bundle> expectedOrder = Arrays.asList(systemBundle, chainTest, chainTestA, chainTestB, chainTestC, chainTestD);
+		assertEquals("Wrong stopping order", expectedOrder.toArray(), stoppingOrder.toArray());
+	}
+
 	private static File[] createBundles(File outputDir, int bundleCount) throws IOException {
 		outputDir.mkdirs();