aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jwr...@apache.org
Subject svn commit: r1428038 - in /aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal: Activator.java BundleEventHook.java
Date Wed, 02 Jan 2013 21:02:22 GMT
Author: jwross
Date: Wed Jan  2 21:02:22 2013
New Revision: 1428038

URL: http://svn.apache.org/viewvc?rev=1428038&view=rev
Log:
[ARIES-992] Get an IllegalStateException in BundleEventHook.handleExplicitlyInstalledBundleBundleContext

This happens when explicitly installing or uninstalling bundles while the subsystems bundle
is deactivating.
The bundle event hook must be blocked while the root subsystem is being stopped. The blocked
events then proceed
once deactivation is complete which results in the exception since the activator instance
is no longer valid.
Events are now queued while subsystems is shutting down, as they are during initialization.
Once the shutdown is
complete and the event hook has been unregistered, any remaining events are processed prior
to returning from the
BundleActivator.stop() method.

Modified:
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
    aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java?rev=1428038&r1=1428037&r2=1428038&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
(original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/Activator.java
Wed Jan  2 21:02:22 2013
@@ -66,7 +66,9 @@ public class Activator implements Bundle
 		logger.debug(LOG_EXIT, "checkInstance");
 	}
 	
-	private BundleContext bundleContext;
+	// @GuardedBy("this")
+	private BundleEventHook bundleEventHook;
+	private volatile BundleContext bundleContext;
 	private volatile Coordinator coordinator;
 	private volatile ModelledResourceManager modelledResourceManager;
 	private volatile SubsystemServiceRegistrar registrar;
@@ -152,7 +154,7 @@ public class Activator implements Bundle
 		synchronized (Activator.class) {
 			instance = Activator.this;
 		}
-		BundleEventHook hook = registerBundleEventHook();
+		registerBundleEventHook();
 		try {
 			subsystems = new Subsystems();
 		}
@@ -166,12 +168,13 @@ public class Activator implements Bundle
 		registrar = new SubsystemServiceRegistrar(bundleContext);
 		BasicSubsystem root = subsystems.getRootSubsystem();
 		root.start();
-		hook.activate();
+		bundleEventHook.activate();
 	}
 	
 	private void deactivate() {
 		if (!isActive())
 			return;
+		bundleEventHook.deactivate();
 		new StopAction(subsystems.getRootSubsystem(), subsystems.getRootSubsystem(), true).run();
 		for (ServiceRegistration<?> registration : registrations) {
 			try {
@@ -181,6 +184,7 @@ public class Activator implements Bundle
 				logger.debug("Service had already been unregistered", e);
 			}
 		}
+		bundleEventHook.processPendingEvents();
 		synchronized (Activator.class) {
 			instance = null;
 		}
@@ -229,12 +233,11 @@ public class Activator implements Bundle
 		}
 	}
 	
-	private BundleEventHook registerBundleEventHook() {
+	private void registerBundleEventHook() {
 		Dictionary<String, Object> properties = new Hashtable<String, Object>(1);
 		properties.put(org.osgi.framework.Constants.SERVICE_RANKING, Integer.MAX_VALUE);
-		BundleEventHook result = new BundleEventHook();
-		registrations.add(bundleContext.registerService(EventHook.class, result, properties));
-		return result;
+		bundleEventHook = new BundleEventHook();
+		registrations.add(bundleContext.registerService(EventHook.class, bundleEventHook, properties));
 	}
 	
 	/* Begin ServiceTrackerCustomizer methods */

Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java?rev=1428038&r1=1428037&r2=1428038&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java
(original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/internal/BundleEventHook.java
Wed Jan  2 21:02:22 2013
@@ -28,17 +28,22 @@ import org.osgi.framework.hooks.bundle.E
 import org.osgi.framework.wiring.BundleRevision;
 
 public class BundleEventHook implements EventHook {
+	private final Activator activator;
 	private final ConcurrentHashMap<Bundle, BundleRevision> bundleToRevision;
 	
 	private boolean active;
 	private List<BundleEvent> events;
+	private volatile Subsystems subsystems;
 	
 	public BundleEventHook() {
+		activator = Activator.getInstance();
 		bundleToRevision = new ConcurrentHashMap<Bundle, BundleRevision>();
 	}
 	
 	@Override
 	public void event(BundleEvent event, Collection<BundleContext> contexts) {
+		if ((event.getType() & (BundleEvent.INSTALLED | BundleEvent.UNINSTALLED)) == 0)
+			return;
 		// Protected against deadlock when the bundle event hook receives an
 		// event before subsystems has fully initialized, in which case the
 		// events are queued and processed once initialization is complete.
@@ -50,6 +55,39 @@ public class BundleEventHook implements 
 				return;
 			}
 		}
+		handleEvent(event);
+	}
+	
+	// Events must be processed in order. Don't allow events to go through
+	// synchronously before all pending events have been processed.
+	synchronized void activate() {
+		active = true;
+		processPendingEvents();
+	}
+	
+	synchronized void deactivate() {
+		active = false;
+	}
+	
+	synchronized void processPendingEvents() {
+		if (events == null)
+			return;
+		for (BundleEvent event : events)
+			handleEvent(event);
+		events = null;
+	}
+	
+	private Subsystems getSubsystems() {
+		if (subsystems == null) {
+			synchronized (this) {
+				if (subsystems == null)
+					subsystems = activator.getSubsystems();
+			}
+		}
+		return subsystems;
+	}
+	
+	private void handleEvent(BundleEvent event) {
 		switch (event.getType()) {
 			case BundleEvent.INSTALLED:
 				handleInstalledEvent(event);
@@ -62,20 +100,11 @@ public class BundleEventHook implements 
 		}
 	}
 	
-	synchronized void activate() {
-		active = true;
-		if (events == null)
-			return;
-		for (BundleEvent event : events)
-			event(event, null);
-		events = null;
-	}
-	
 	private void handleExplicitlyInstalledBundleBundleContext(BundleRevision originRevision,
BundleRevision bundleRevision) {
 		// The bundle needs to be associated with all subsystems that are 
 		// associated with the bundle whose context was used to install the 
 		// bundle.
-		Collection<BasicSubsystem> subsystems = Activator.getInstance().getSubsystems().getSubsystemsReferencing(originRevision);
+		Collection<BasicSubsystem> subsystems = getSubsystems().getSubsystemsReferencing(originRevision);
 		if (subsystems.isEmpty())
 			throw new IllegalStateException("Orphaned bundle revision detected: " + originRevision);
 		for (BasicSubsystem s : subsystems)
@@ -85,9 +114,9 @@ public class BundleEventHook implements 
 	private void handleExplicitlyInstalledBundleRegionDigraph(Bundle origin, BundleRevision
bundleRevision) {
 			// The bundle needs to be associated with the scoped subsystem of 
 			// the region used to install the bundle.
-			RegionDigraph digraph = Activator.getInstance().getRegionDigraph();
+			RegionDigraph digraph = activator.getRegionDigraph();
 			Region region = digraph.getRegion(origin);
-			for (BasicSubsystem s : Activator.getInstance().getSubsystems().getSubsystems()) {
+			for (BasicSubsystem s : getSubsystems().getSubsystems()) {
 				if ((s.isApplication() || s.isComposite())
 						&& region.equals(s.getRegion())) {
 					Utils.installResource(bundleRevision, s);



Mime
View raw message