Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlyn Normington2012-08-31 07:56:27 +0000
committerGlyn Normington2012-08-31 07:56:27 +0000
commit0e0e5cb225049946828464aeb4fea04be2e1c3b8 (patch)
treea8ea5c215086e19301e196b63b971b834766d4d2
parent0d4dd25afb3de213dc023b29a2f95f58e619fc85 (diff)
downloadorg.eclipse.gemini.blueprint-0e0e5cb225049946828464aeb4fea04be2e1c3b8.tar.gz
org.eclipse.gemini.blueprint-0e0e5cb225049946828464aeb4fea04be2e1c3b8.tar.xz
org.eclipse.gemini.blueprint-0e0e5cb225049946828464aeb4fea04be2e1c3b8.zip
388496: catch IllegalStateExceptions in ShutdownSorter
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java38
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/BundleDependencyComparator.java186
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ComparatorServiceDependencySorter.java154
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ServiceDependencySorter.java45
-rw-r--r--extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ShutdownSorter.java74
-rw-r--r--extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/AbstractServiceDependencySorterTest.java392
-rw-r--r--extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/ComparatorServiceDependencySorterTest.java30
7 files changed, 59 insertions, 860 deletions
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java
index c7d2b55..5ad01f2 100644
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java
+++ b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/activator/LifecycleManager.java
@@ -17,32 +17,18 @@ package org.eclipse.gemini.blueprint.extender.internal.activator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.ServiceReference;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.core.task.SyncTaskExecutor;
-import org.springframework.core.task.TaskExecutor;
import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
import org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext;
import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;
import org.eclipse.gemini.blueprint.extender.OsgiApplicationContextCreator;
import org.eclipse.gemini.blueprint.extender.OsgiBeanFactoryPostProcessor;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.BundleDependencyComparator;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ComparatorServiceDependencySorter;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ServiceDependencySorter;
import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ShutdownSorter;
import org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor;
import org.eclipse.gemini.blueprint.extender.internal.support.ExtenderConfiguration;
@@ -52,6 +38,12 @@ import org.eclipse.gemini.blueprint.extender.internal.util.concurrent.RunnableTi
import org.eclipse.gemini.blueprint.extender.support.ApplicationContextConfiguration;
import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;
import org.eclipse.gemini.blueprint.util.OsgiStringUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.core.task.SyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
/**
* Manager handling the startup/shutdown threading issues regarding OSGi contexts. Used by {@link ContextLoaderListener}
@@ -94,9 +86,6 @@ class LifecycleManager implements DisposableBean {
*/
private final TaskExecutor sameThreadTaskExecutor = new SyncTaskExecutor();
- /** Service-based dependency sorter for shutdown */
- private final ServiceDependencySorter shutdownDependencySorter = new ComparatorServiceDependencySorter();
-
private final OsgiBundleApplicationContextEventMulticaster multicaster;
private final ExtenderConfiguration extenderConfiguration;
@@ -360,9 +349,7 @@ class LifecycleManager implements DisposableBean {
final Object[] contextClosingDown = new Object[1];
for (Bundle shutdownBundle : candidates) {
- Long id = new Long(shutdownBundle.getBundleId());
- final ConfigurableOsgiBundleApplicationContext context =
- (ConfigurableOsgiBundleApplicationContext) managedContexts.get(id);
+ final ConfigurableOsgiBundleApplicationContext context = getManagedContext(shutdownBundle);
if (context != null) {
closedContexts.add(context);
// add a new runnable
@@ -405,6 +392,17 @@ class LifecycleManager implements DisposableBean {
stopTaskExecutor();
}
+ public ConfigurableOsgiBundleApplicationContext getManagedContext(Bundle bundle) {
+ ConfigurableOsgiBundleApplicationContext context = null;
+ try {
+ Long id = new Long(bundle.getBundleId());
+ context = (ConfigurableOsgiBundleApplicationContext) managedContexts.get(id);
+ } catch (IllegalStateException _) {
+ // ignore
+ }
+ return context;
+ }
+
/**
* Do some additional waiting so the service dependency listeners detect the shutdown.
*/
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/BundleDependencyComparator.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/BundleDependencyComparator.java
deleted file mode 100644
index cd0f705..0000000
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/BundleDependencyComparator.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * 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.
- * Oracle Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown;
-
-import java.io.Serializable;
-import java.util.Comparator;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext;
-import org.eclipse.gemini.blueprint.service.exporter.OsgiServicePropertiesResolver;
-import org.eclipse.gemini.blueprint.util.OsgiServiceReferenceUtils;
-import org.springframework.util.ObjectUtils;
-
-/**
- * Null safe service-based dependency sorter for bundles. Sorts bundles based on their services using the following
- * algorithm: <p/> <ol> <li> if two bundles are connected (transitively) then the bundle that exports the service with
- * lowest ranking id, will be considered lower. </li> <li> if the ranks are equal, then the service id (which is
- * guaranteed to be unique) will be considered. </li> <li> if the bundles are not related then they will be sorted based
- * on their symbolic name. </li> </ol>
- *
- * @author Hal Hildebrand
- * @author Andy Piper
- * @author Costin Leau
- */
-public class BundleDependencyComparator implements Comparator, Serializable {
-
- private static final long serialVersionUID = -108354908478230663L;
-
- private static final Log log = LogFactory.getLog(BundleDependencyComparator.class);
-
- /**
- * Simple method checking whether the given service reference points to a spring managed service or not. Checks for
- *
- * @param reference reference to the OSGi service
- * @return true if the service is spring managed, false otherwise
- */
- public static boolean isSpringManagedService(ServiceReference reference) {
- if (reference == null)
- return false;
- return (reference.getProperty(OsgiServicePropertiesResolver.BEAN_NAME_PROPERTY_KEY) != null ||
- reference.getProperty(OsgiServicePropertiesResolver.SPRING_DM_BEAN_NAME_PROPERTY_KEY) != null
- || reference.getProperty(ConfigurableOsgiBundleApplicationContext.APPLICATION_CONTEXT_SERVICE_PROPERTY_NAME) != null
- || reference.getProperty(ConfigurableOsgiBundleApplicationContext.SPRING_DM_APPLICATION_CONTEXT_SERVICE_PROPERTY_NAME) != null);
- }
-
- private static ServiceReference[] excludeNonSpringManagedServices(ServiceReference[] references) {
- if (ObjectUtils.isEmpty(references))
- return references;
-
- int count = 0;
- for (int i = 0; i < references.length; i++) {
- if (!isSpringManagedService(references[i]))
- references[i] = null;
- else
- count++;
- }
-
- if (count == references.length)
- return references;
-
- ServiceReference[] refs = new ServiceReference[count];
- int j = 0;
- for (int i = 0; i < references.length; i++) {
- if (references[i] != null) {
- refs[j] = references[i];
- j++;
- }
- }
-
- return refs;
- }
-
- /**
- * Answer whether Bundle a is higher or lower depending on the ranking and id of its exported services. This is used
- * as a tie-breaker for circular references.
- */
- protected static int compareUsingServiceRankingAndId(Bundle a, Bundle b) {
- ServiceReference[] aservices = excludeNonSpringManagedServices(a.getRegisteredServices());
- ServiceReference[] bservices = excludeNonSpringManagedServices(b.getRegisteredServices());
-
- boolean trace = log.isTraceEnabled();
-
- // this case should not occur
- if (ObjectUtils.isEmpty(aservices) && ObjectUtils.isEmpty(bservices)) {
- if (trace)
- log.trace("both services have 0 services; sorting based on id");
- return signum((int) (a.getBundleId() - b.getBundleId()));
- } else if (aservices == null) {
- return -1;
- } else if (bservices == null) {
- return 1;
- }
-
- // Look for the *lowest* highest ranked service in each bundle
- // i.e. take a look at each bundle, find the highest ranking service
- // and compare it to the other bundle
- // this means that the service with the highest ranking service will
- // be shutdown last
-
- int aRank = findHighestServiceRanking(aservices);
- int bRank = findHighestServiceRanking(bservices);
-
- // since we are looking for the minimum, invert the substraction
- // (the higher bundle is the one with the lowest rank)
- if (aRank != bRank) {
- int compare = -(bRank - aRank);
- if (trace) {
- int min = (compare > 0 ? (int) bRank : (int) aRank);
- log.trace("sorting based on lowest-service-ranking won by bundle" + (compare > 0 ? "1" : "2")
- + " w/ service id " + min);
- }
-
- return signum(-(bRank - aRank));
- }
-
- // Look for the highest id in each bundle (i.e. started last).
- long aMaxId = findHighestServiceId(aservices);
- long bMaxId = findHighestServiceId(bservices);
-
- if (aMaxId != bMaxId) {
- int compare = (int) (bMaxId - aMaxId);
- if (trace) {
- int max = (compare > 0 ? (int) bMaxId : (int) aMaxId);
- log.trace("sorting based on highest-service-id won by bundle " + (compare > 0 ? "1" : "2")
- + " w/ service id " + max);
- }
-
- return signum(compare);
- }
-
- return signum((int) (a.getBundleId() - b.getBundleId()));
- }
-
- /**
- * Find the highest service ranking. This might come as unexpected however, since a bundle can export multiple
- * services, we have to find the minimum between the maximum services in each bundle - i.e. the bundle with the
- * highest service ranking will win.
- *
- * @param refs
- */
- private static int findHighestServiceRanking(ServiceReference[] refs) {
- int maxRank = Integer.MIN_VALUE;
- for (int i = 0; i < refs.length; i++) {
- int currentRank = OsgiServiceReferenceUtils.getServiceRanking(refs[i]);
- if (currentRank > maxRank)
- maxRank = currentRank;
- }
-
- return maxRank;
- }
-
- private static long findHighestServiceId(ServiceReference[] refs) {
- long maxId = Long.MIN_VALUE;
- for (int i = 0; i < refs.length; i++) {
- long currentId = OsgiServiceReferenceUtils.getServiceId(refs[i]);
- if (currentId > maxId)
- maxId = currentId;
- }
-
- return maxId;
- }
-
- private static int signum(int a) {
- return a < 0 ? -1 : a == 0 ? 0 : 1;
- }
-
- public int compare(Object a, Object b) {
- return compareUsingServiceRankingAndId((Bundle) a, (Bundle) b);
- }
-} \ No newline at end of file
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ComparatorServiceDependencySorter.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ComparatorServiceDependencySorter.java
deleted file mode 100644
index 6004a10..0000000
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ComparatorServiceDependencySorter.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * 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.
- * Oracle Inc.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown;
-
-import java.util.Arrays;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-
-/**
- * Comparator based dependency sorter.
- *
- * @author Costin Leau
- * @author Andy Piper
- */
-public class ComparatorServiceDependencySorter implements ServiceDependencySorter {
-
- public Bundle[] computeServiceDependencyGraph(Bundle[] bundles) {
- TarganStronglyConnectedSorter parser = new TarganStronglyConnectedSorter(bundles);
- return parser.computeServiceDependencyGraph();
- }
-
- /**
- * Strongly Connected Component graph algorithm due to R. E. Targan, 1972. The implementation
- * is adapted from "Algorithms in C" by Robert Sedgewick. In particular we make use of the property that
- * non-connected components are traversed depth-first and so provide us with a regular dependency graph.
- * Strongly connected components (a.k.a cycles) are gathered in a batch which gives us an opportunity to do
- * futher sorting before output.
- */
- public static class TarganStronglyConnectedSorter {
- private BundleDependencyComparator comparator = new BundleDependencyComparator();
-
- // Note that variable names reflect those in Sedgewick for easy comparison.
- private int id = 0;
- private int[] val; // visited list
- private int[] stack;
- private int p = 0; // current stack position
- private Node[] adj; // adjacency list of edges
- private int V; // the number of Vertices
- private Bundle[] bundles; // the output bundle list
- private Bundle[] sourcebundles; // the input bundle list
- private int index = 0; // current position in output list
-
- private static class Node {
- private int v;
- private Node next;
-
- public Node(int v, Node next) {
- this.v = v;
- this.next = next;
- }
-
- public int v() {
- return v;
- }
-
- public Node next() {
- return next;
- }
- }
-
- public TarganStronglyConnectedSorter(Bundle[] bundles) {
- this.V = bundles.length;
- this.bundles = new Bundle[V];
- this.sourcebundles = bundles;
- val = new int[V + 1];
- adj = new Node[V + 1];
- stack = new int[V + 1];
- }
-
- public Bundle[] computeServiceDependencyGraph() {
- // Zero adjacency matrix
- for (int k = 1; k <= V; k++) {
- val[k] = 0;
- adj[k] = null;
- }
- // Build adjacency matrix, x -> y
- // This probably could be more efficient
- for (int y = 1; y <= V; y++) {
- for (int x = 1; x <= V; x++) {
- if (references(sourcebundles[x - 1], sourcebundles[y - 1])) {
- adj[y] = new Node(x, adj[y]);
- }
- }
- }
- // Modified depth-first search of the nodes
- for (int k = 1; k <= V; k++) {
- if (val[k] == 0) visit(k);
- }
- return bundles;
- }
-
- private int visit(int k) {
- int m, min;
- val[k] = ++id;
- min = id;
- stack[p++] = k;
- for (Node t = adj[k]; t != null; t = t.next()) {
- m = (val[t.v()] == 0) ? visit(t.v()) : val[t.v()];
- if (m < min) min = m;
- }
- if (min == val[k]) {
- int subset = index;
- while (stack[p] != k) {
- int visited = stack[--p];
- bundles[index++] = sourcebundles[visited - 1];
- val[visited] = V + 1;
- }
- // Strongly connected set, so sort via ranking
- if (index > subset) {
- Arrays.sort(bundles, subset, index, comparator);
- }
- }
- return min;
- }
-
- /**
- * Answer whether Bundle b is directly referenced by Bundle a
- */
- protected static boolean references(Bundle a, Bundle b) {
- ServiceReference[] services = b.getRegisteredServices();
- if (services == null) {
- return false;
- }
- for (int i = 0; i < services.length; i++) {
- // filter on spring managed services
- if (BundleDependencyComparator.isSpringManagedService(services[i])) {
- Bundle[] referingBundles = services[i].getUsingBundles();
- if (referingBundles != null) {
- for (int j = 0; j < referingBundles.length; j++) {
- if (a.equals(referingBundles[j])) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- }
-}
diff --git a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ServiceDependencySorter.java b/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ServiceDependencySorter.java
deleted file mode 100644
index 6d424e5..0000000
--- a/extender/src/main/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/shutdown/ServiceDependencySorter.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * 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.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown;
-
-import org.osgi.framework.Bundle;
-
-/**
- * SPI for sorting OSGi bundles based on their service dependency. Given a
- * number of bundles, implementors of this interface will return a list
- * referencing the bundles in the order in which they should be shutdown based
- * on their OSGi service dependencies.
- * <p/>
- * It is considered that bundle A depends on bundle B if A uses a service that
- * belongs to a bundle which depends on B or is B itself. Note that bundles can
- * depend on each other : A -> B -> A.
- * <p/>
- * Thus implementations should 'sort' direct, circular graphs without any
- * guarantee on the node used for start.
- *
- * @author Costin Leau
- *
- */
-public interface ServiceDependencySorter {
-
- /**
- * Given a number of bundles, determine the dependency between each other and compute
- * the dependency tree.
- *
- * @param bundles array of bundles
- * @return an array of bundles, sorted out by their dependency.
- */
- Bundle[] computeServiceDependencyGraph(Bundle[] bundles);
-}
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 aaa6afe..2b84337 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
@@ -47,7 +47,7 @@ public abstract class ShutdownSorter {
* called after all the returned bundles have been destroyed until the list is empty.
*
* @param managedBundles
- * @return
+ * @return sorted collection of Bundles
*/
public static Collection<Bundle> getBundles(Collection<Bundle> managedBundles) {
@@ -74,37 +74,41 @@ public abstract class ShutdownSorter {
boolean trace = log.isTraceEnabled();
for (Bundle bundle : unsorted) {
- String bundleToString = null;
- if (trace) {
- bundleToString = OsgiStringUtils.nullSafeSymbolicName(bundle);
- }
- ServiceReference[] services = bundle.getRegisteredServices();
- if (ObjectUtils.isEmpty(services)) {
- if (trace) {
- log.trace("Bundle " + bundleToString + " has no registered services; added for shutdown");
- }
- unused.add(bundle);
- } else {
- boolean unusedBundle = true;
- for (ServiceReference serviceReference : services) {
- Bundle[] usingBundles = serviceReference.getUsingBundles();
- if (!ObjectUtils.isEmpty(usingBundles)) {
- if (trace)
- log.trace("Bundle " + bundleToString
- + " has registered services in use; postponing shutdown. The using bundles are "
- + Arrays.toString(usingBundles));
- unusedBundle = false;
- break;
- }
-
- }
- if (unusedBundle) {
- if (trace) {
- log.trace("Bundle " + bundleToString + " has unused registered services; added for shutdown");
- }
- unused.add(bundle);
- }
- }
+ try {
+ String bundleToString = null;
+ if (trace) {
+ bundleToString = OsgiStringUtils.nullSafeSymbolicName(bundle);
+ }
+ ServiceReference[] services = bundle.getRegisteredServices();
+ if (ObjectUtils.isEmpty(services)) {
+ if (trace) {
+ log.trace("Bundle " + bundleToString + " has no registered services; added for shutdown");
+ }
+ unused.add(bundle);
+ } else {
+ boolean unusedBundle = true;
+ for (ServiceReference serviceReference : services) {
+ Bundle[] usingBundles = serviceReference.getUsingBundles();
+ if (!ObjectUtils.isEmpty(usingBundles)) {
+ if (trace)
+ log.trace("Bundle " + bundleToString + " has registered services in use; postponing shutdown. The using bundles are "
+ + Arrays.toString(usingBundles));
+ unusedBundle = false;
+ break;
+ }
+
+ }
+ if (unusedBundle) {
+ if (trace) {
+ log.trace("Bundle " + bundleToString + " has unused registered services; added for shutdown");
+ }
+ unused.add(bundle);
+ }
+ }
+ }
+ catch (IllegalStateException _) {
+ unused.add(bundle);
+ }
}
Collections.sort(unused, ReverseBundleIdSorter.INSTANCE);
@@ -220,7 +224,11 @@ public abstract class ShutdownSorter {
private static Comparator<Bundle> INSTANCE = new ReverseBundleIdSorter();
public int compare(Bundle o1, Bundle o2) {
- return (int) (o2.getBundleId() - o1.getBundleId());
+ try {
+ return (int) (o2.getBundleId() - o1.getBundleId());
+ } catch (IllegalStateException _) {
+ return o1 == o2 ? 0 : 1; // cannot tell which is larger, but must provide a total ordering
+ }
}
}
} \ No newline at end of file
diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/AbstractServiceDependencySorterTest.java b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/AbstractServiceDependencySorterTest.java
deleted file mode 100644
index fe2bb85..0000000
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/AbstractServiceDependencySorterTest.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * 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.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.dependencies;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-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.ServiceDependencySorter;
-import org.osgi.framework.Bundle;
-import org.springframework.util.ObjectUtils;
-
-/**
- * Base testing suite for ordering bundles based on service dependencies. To
- * visualize the graph, see the .dot files in the same folder which can read
- * through Graphviz tool.
- *
- * @author Costin Leau
- */
-public abstract class AbstractServiceDependencySorterTest extends TestCase {
-
- protected ServiceDependencySorter sorter;
-
- private int count = 1;
-
- protected void setUp() throws Exception {
- sorter = createSorter();
- }
-
- protected abstract ServiceDependencySorter createSorter();
-
- protected void tearDown() throws Exception {
- sorter = null;
- }
-
- // A -> B -> C
- public void testSimpleTree() {
- DependencyMockBundle a = new DependencyMockBundle("A");
- DependencyMockBundle b = new DependencyMockBundle("B");
- DependencyMockBundle c = new DependencyMockBundle("C");
-
- // A -> B -> C
- a.setDependentOn(b);
- b.setDependentOn(c);
-
- testDependencyTreeWithShuffle(new Bundle[]{c, b, a}, new Bundle[]{a, b, c});
- }
-
- // A -> B, C, D
- // B -> C, E
- // C -> E
- // D -> B
- public void testMediumTree() {
- 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");
-
- a.setDependentOn(new Bundle[]{d, c, b});
- b.setDependentOn(new Bundle[]{e, c});
- c.setDependentOn(e);
- d.setDependentOn(b);
-
- testDependencyTreeWithShuffle(new Bundle[]{e, c, b, d, a}, new Bundle[]{a, b, c, d, e});
- }
-
- // A -> B, C, D
- // B -> C
- // D -> B, E
- // E -> F, G
- // F -> G
- // H -> G
- // I -> H, J
-
- // depending on the order there are multiple shutdown orders
- public void testLargeTree() {
- 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 f = new DependencyMockBundle("f");
- DependencyMockBundle g = new DependencyMockBundle("g");
- DependencyMockBundle h = new DependencyMockBundle("h");
- DependencyMockBundle i = new DependencyMockBundle("i");
- DependencyMockBundle j = new DependencyMockBundle("j");
-
- a.setDependentOn(new Bundle[]{b, c, d});
- b.setDependentOn(c);
- d.setDependentOn(new Bundle[]{b, e});
- e.setDependentOn(new Bundle[]{f, g});
- f.setDependentOn(g);
- h.setDependentOn(g);
- i.setDependentOn(new Bundle[]{h, j});
-
- testDependencyTree(new Bundle[]{g, f, e, c, b, d, a, h, j, i}, new Bundle[]{a, b, c, d, e, f,
- g, h, i, j});
- }
-
- // A -> B,D
- // B -> C, E
- // C
- // D -> B, C
- // E -> C
- public void testComplexTree() {
- 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");
-
- a.setDependentOn(new Bundle[]{b, d});
- b.setDependentOn(new Bundle[]{c, e});
- d.setDependentOn(new Bundle[]{b, c});
- e.setDependentOn(new Bundle[]{c});
-
- testDependencyTreeWithShuffle(new Bundle[]{c, e, b, d, a}, new Bundle[]{a, b, c, d, e});
- }
-
- // Although this is an interesting test, the shutdown logic does not require that
- // it pass and the current algorithm does not handle this case.
- public void XtestMissingMiddle() 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");
-
- // Sets dependency A -> B -> C -> D -> E
- B.setDependentOn(A);
- C.setDependentOn(new Bundle[]{B});
- D.setDependentOn(new Bundle[]{C});
- E.setDependentOn(new Bundle[]{D});
-
- testDependencyTree(new Bundle[]{A, C, E}, new Bundle[]{C, E, A});
- }
-
- // //////////
- // CIRCULAR TREES
- // /////////
-
- // A -> B (id = 1)
- // B -> A (id = 2)
- // B -> A has to be stopped first since it was created last (highest id)
- public void testSimpleCircularTreeTieOnServiceRankingUsingServiceId() {
- DependencyMockBundle a = new DependencyMockBundle("A");
- DependencyMockBundle b = new DependencyMockBundle("B");
-
- b.setDependentOn(a, 0, 2);
- a.setDependentOn(b, 0, 1);
-
- Bundle[] expectedVer1 = new Bundle[]{a, b};
- Bundle[] expectedVer2 = new Bundle[]{b, a};
-
- // we should get the same order always (B should be stopped first)
- assertTrue(Arrays.equals(expectedVer2, sorter.computeServiceDependencyGraph(expectedVer1)));
- assertTrue(Arrays.equals(expectedVer2, sorter.computeServiceDependencyGraph(expectedVer2)));
- }
-
- public void testSimpleCircularTreeUsingServiceRanking() {
- DependencyMockBundle a = new DependencyMockBundle("A");
- DependencyMockBundle b = new DependencyMockBundle("B");
-
- b.setDependentOn(a);
- a.setDependentOn(b);
-
- testDependencyTreeWithShuffle(new Bundle[]{a, b}, new Bundle[]{a, b});
- }
-
- // A -> B, C
- // B -> C, D
- // C -> D
- // D -> A
- public void testMediumCircularCycle() {
- DependencyMockBundle a = new DependencyMockBundle("A");
- DependencyMockBundle b = new DependencyMockBundle("B");
- DependencyMockBundle c = new DependencyMockBundle("C");
- DependencyMockBundle d = new DependencyMockBundle("D");
-
- a.setDependentOn(new Bundle[]{b, c});
- b.setDependentOn(new Bundle[]{c, d});
- c.setDependentOn(d);
- d.setDependentOn(a);
-
- testDependencyTreeWithShuffle(new Bundle[]{d, c, b, a}, new Bundle[]{a, b, c, d});
- }
-
- // A -> B, D
- // B -> C, E
- // C -> D
- // D -> B, C
- // E -> C
- // E should be stopped first, since it is the last service started
- public void testComplexCyclicTree() {
- 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");
-
- a.setDependentOn(new Bundle[]{b, d});
- b.setDependentOn(new Bundle[]{c, e});
- c.setDependentOn(d);
- d.setDependentOn(new Bundle[]{b, c});
- e.setDependentOn(c);
-
- testDependencyTreeWithShuffle(new Bundle[]{e, d, c, b, a}, new Bundle[]{a, b, c, d, e});
- }
-
- public void testCircularReferenceId() 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");
-
- // Sets dependency A -> B -> C -> D -> E -> A
- // A has lowest id so gets shutdown last (started first).
- A.setDependentOn(new Bundle[]{E}, 0, 0);
- B.setDependentOn(new Bundle[]{A}, 0, 1);
- C.setDependentOn(new Bundle[]{B}, 0, 2);
- D.setDependentOn(new Bundle[]{C}, 0, 3);
- E.setDependentOn(new Bundle[]{D}, 0, 4);
-
- testDependencyTreeWithShuffle(new Bundle[]{E, D, C, B, A}, new Bundle[]{E, D, C, B, A});
- }
-
- public void tstCircularReferenceIdMulti() throws Exception {
- DependencyMockBundle A = new DependencyMockBundle("A");
- DependencyMockBundle B = new DependencyMockBundle("B");
- DependencyMockBundle C = new DependencyMockBundle("C");
-
- // Sets dependency A -> C -> B -> A
- // A has lowest id so gets shutdown last (started first).
- // B should go first since its service was started last (id = 4)
- A.setDependentOn(new Bundle[]{C}, 0, 0);
- B.setDependentOn(new Bundle[]{A, A}, new int[]{0, 0}, new long[]{4, 1});
- C.setDependentOn(new Bundle[]{B}, 0, 2);
-
- testDependencyTreeWithShuffle(new Bundle[]{B, C, A}, new Bundle[]{C, B, A});
- }
-
- public void testCircularReferenceRankMulti() throws Exception {
- DependencyMockBundle A = new DependencyMockBundle("A");
- DependencyMockBundle B = new DependencyMockBundle("B");
- DependencyMockBundle C = new DependencyMockBundle("C");
-
- // Sets dependency A -> B -> C -> A
- // B has highest rank so gets shutdown last (its started first).
- // C should go second since its service has the second ranking (2)
- // which means A should go first
- A.setDependentOn(new Bundle[]{B}, 0, 0);
- B.setDependentOn(new Bundle[]{C, C}, new int[]{0, 3}, new long[]{0, 0});
- C.setDependentOn(new Bundle[]{A}, 2, 0);
-
- testDependencyTreeWithShuffle(new Bundle[]{A, C, B}, new Bundle[]{C, B, A});
- }
-
- public void testCircularReferenceReference() 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");
-
- // Sets dependency A -> B -> C -> D -> E -> A
- // A has higher ranking so gets shutdown last
-
- // A -> E
- // B -> A
- // C -> B
- // D -> C
- // E -> D
- // E -> D -> C -> B -> A -> E
- A.setDependentOn(new Bundle[]{E}, 4, 0);
- B.setDependentOn(new Bundle[]{A}, 3, 1);
- C.setDependentOn(new Bundle[]{B}, 2, 2);
- D.setDependentOn(new Bundle[]{C}, 1, 3);
- E.setDependentOn(new Bundle[]{D}, 0, 4);
-
- testDependencyTreeWithShuffle(new Bundle[]{E, D, C, B, A}, new Bundle[]{E, D, C, B, A});
- }
-
- public void testForest() 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 F = new DependencyMockBundle("F");
- DependencyMockBundle G = new DependencyMockBundle("G");
- DependencyMockBundle H = new DependencyMockBundle("H");
- DependencyMockBundle I = new DependencyMockBundle("I");
- DependencyMockBundle J = new DependencyMockBundle("J");
-
- // Sets dependency A -> B -> C, B -> D -> E
- A.setDependentOn(new Bundle[]{B});
- B.setDependentOn(new Bundle[]{C, D});
- D.setDependentOn(new Bundle[]{E});
-
- // Sets dependency F -> G, F -> H
- F.setDependentOn(new Bundle[]{G, H});
-
- // Sets dependency I -> J
- I.setDependentOn(new Bundle[]{J});
-
- testDependencyTree(new Bundle[]{G, H, F, E, D, J, C, B, A, I}, new Bundle[]{F, D, J, B, E, A,
- H, I, G, C});
- }
-
- public void testInversedForest() 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 F = new DependencyMockBundle("F");
- DependencyMockBundle G = new DependencyMockBundle("G");
- DependencyMockBundle H = new DependencyMockBundle("H");
- DependencyMockBundle I = new DependencyMockBundle("I");
- DependencyMockBundle J = new DependencyMockBundle("J");
-
- // C -> B -> A, E -> D -> B
- B.setDependentOn(new Bundle[]{A});
- C.setDependentOn(new Bundle[]{B});
- D.setDependentOn(new Bundle[]{B});
- E.setDependentOn(new Bundle[]{D});
-
- // Sets dependency G -> F, H -> F
- G.setDependentOn(new Bundle[]{F});
- H.setDependentOn(new Bundle[]{F});
-
- // Sets dependency J -> I
- J.setDependentOn(new Bundle[]{I});
-
- testDependencyTree(new Bundle[]{F, A, B, D, I, J, E, H, G, C}, new Bundle[]{F, D, J, B, E, A,
- H, I, G, C});
- }
-
- /**
- * Test the resulting tree after shuffling the input bundles several times.
- *
- * @param expected
- * @param bundles
- * @return
- */
- protected void testDependencyTree(Bundle[] expected, Bundle[] bundles) {
- Bundle[] tree = sorter.computeServiceDependencyGraph(bundles);
- assertTrue("array [" + ObjectUtils.nullSafeToString(tree) + "] does not match ["
- + ObjectUtils.nullSafeToString(expected) + "] for input [" + ObjectUtils.nullSafeToString(bundles)
- + "]", Arrays.equals(expected, tree));
-
- }
-
- protected void testDependencyTreeWithShuffle(Bundle[] expected, Bundle[] bundles) {
- List input = new ArrayList(bundles.length);
-
- for (int i = 0; i < bundles.length; i++) {
- input.add(bundles[i]);
- }
-
- // shuffle based on the number of elements
- for (int i = 0; i < bundles.length; i++) {
- testDependencyTree(expected, (Bundle[]) input.toArray(new Bundle[bundles.length]));
- Collections.shuffle(input);
- }
-
- count += bundles.length;
- }
-
- public int countTestCases() {
- return count;
- }
-
-}
diff --git a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/ComparatorServiceDependencySorterTest.java b/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/ComparatorServiceDependencySorterTest.java
deleted file mode 100644
index 8eb1b50..0000000
--- a/extender/src/test/java/org/eclipse/gemini/blueprint/extender/internal/dependencies/ComparatorServiceDependencySorterTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * 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.
- *****************************************************************************/
-
-package org.eclipse.gemini.blueprint.extender.internal.dependencies;
-
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ComparatorServiceDependencySorter;
-import org.eclipse.gemini.blueprint.extender.internal.dependencies.shutdown.ServiceDependencySorter;
-
-/**
- * @author Costin Leau
- *
- */
-public class ComparatorServiceDependencySorterTest extends AbstractServiceDependencySorterTest {
-
- protected ServiceDependencySorter createSorter() {
- return new ComparatorServiceDependencySorter();
- }
-
-}

Back to the top