Index: osgi-javaee/osgi-javaee-base/src/main/java/org/glassfish/osgijavaeebase/OSGiContainer.java =================================================================== --- osgi-javaee/osgi-javaee-base/src/main/java/org/glassfish/osgijavaeebase/OSGiContainer.java (revision 44286) +++ osgi-javaee/osgi-javaee-base/src/main/java/org/glassfish/osgijavaeebase/OSGiContainer.java (working copy) @@ -105,12 +105,12 @@ return shutdown; } - private synchronized void redeploy(Bundle b) throws Exception { - if (isShutdown()) return; + private synchronized OSGiApplicationInfo redeploy(Bundle b) throws Exception { + if (isShutdown()) return null; if (isDeployed(b)) { undeploy(b); } - deploy(b); + return deploy(b); } /** @@ -120,26 +120,33 @@ * * @param b Bundle to be deployed. */ - public synchronized void deploy(Bundle b) { - if (isShutdown()) return; + public synchronized OSGiApplicationInfo deploy(Bundle b) { + if (isShutdown()) return null; + // By the time this extender is processing the bundle, if the bundle has already changed + // state to STOPPING, then cancel the deployment operation. + if (b.getState() == Bundle.STOPPING) { + logger.logp(Level.INFO, "OSGiContainer", "deploy", + "Bundle {0} is already moved to STOPPING state, so it won't be deployed.", new Object[]{b}); + return null; + } OSGiApplicationInfo osgiAppInfo = applications.get(b); if (osgiAppInfo != null) { logger.logp(Level.WARNING, "OSGiContainer", "deploy", "Bundle {0} is already deployed at {1} ", new Object[]{b, osgiAppInfo.getAppInfo().getSource()}); - return; + return null; } ServiceReference/*OSGiDeployer*/ osgiDeployerRef = selectDeployer(b); if (osgiDeployerRef == null) { // No deployer recognises this bundle, so return - return; + return null; } OSGiDeployer osgiDeployer = (OSGiDeployer) context.getService(osgiDeployerRef); if (osgiDeployer == null) { logger.logp(Level.WARNING, "OSGiContainer", "deploy", "Bundle {0} can't be deployed because corresponding deployer {1} has vanished!!!", new Object[]{b, osgiDeployer}); - return; + return null; } // deploy the java ee artifacts @@ -148,7 +155,7 @@ } catch (Exception e) { logger.logp(Level.WARNING, "OSGiContainer", "deploy", "Failed to deploy bundle " + b, e); - return; + return null; } osgiAppInfo.setDeployer(osgiDeployerRef); applications.put(b, osgiAppInfo); @@ -157,6 +164,7 @@ logger.logp(Level.INFO, "OSGiContainer", "deploy", "deployed bundle {0} at {1}", new Object[]{osgiAppInfo.getBundle(), osgiAppInfo.getAppInfo().getSource().getURI()}); + return osgiAppInfo; } /** Index: osgi-javaee/osgi-javaee-base/src/main/java/org/glassfish/osgijavaeebase/JavaEEExtender.java =================================================================== --- osgi-javaee/osgi-javaee-base/src/main/java/org/glassfish/osgijavaeebase/JavaEEExtender.java (revision 44286) +++ osgi-javaee/osgi-javaee-base/src/main/java/org/glassfish/osgijavaeebase/JavaEEExtender.java (working copy) @@ -48,10 +48,8 @@ import org.osgi.util.tracker.BundleTracker; import org.osgi.util.tracker.BundleTrackerCustomizer; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.Map; +import java.util.concurrent.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -103,10 +101,10 @@ executorService.shutdownNow(); } - private synchronized void deploy(Bundle b) { - if (!isStarted()) return; + private synchronized OSGiApplicationInfo deploy(Bundle b) { + if (!isStarted()) return null; try { - c.deploy(b); + return c.deploy(b); } catch (Exception e) { logger.logp(Level.SEVERE, "JavaEEExtender", "deploy", @@ -115,6 +113,7 @@ logger.logp(Level.SEVERE, "JavaEEExtender", "deploy", "Exception Stack Trace", e); } + return null; } private synchronized void undeploy(Bundle b) { @@ -139,15 +138,20 @@ } private class HybridBundleTrackerCustomizer implements BundleTrackerCustomizer { + private Map> deploymentTasks = + new ConcurrentHashMap>(); + public Object addingBundle(final Bundle bundle, BundleEvent event) { if (!isStarted()) return null; final int state = bundle.getState(); if (isReady(event, state)) { - executorService.submit(new Runnable() { - public void run() { - deploy(bundle); + Future future = executorService.submit(new Callable() { + @Override + public OSGiApplicationInfo call() throws Exception { + return deploy(bundle); } }); + deploymentTasks.put(bundle.getBundleId(), future); return bundle; } return null; @@ -169,13 +173,17 @@ public void removedBundle(final Bundle bundle, BundleEvent event, Object object) { if (!isStarted()) return; - Future future = executorService.submit(new Runnable() { - public void run() { - undeploy(bundle); + Future deploymentTask = deploymentTasks.remove(bundle.getBundleId()); + if (deploymentTask == null) { + // We have never seen this bundle before. Ideally we should never get here. + assert(false); + return; + } + try { + OSGiApplicationInfo deployedApp = deploymentTask.get(); + if (deployedApp != null) { + undeploy(bundle); // undeploy synchronously to avoid any deadlock. See GF issue # } - }); - try { - future.get(); } catch (InterruptedException e) { throw new RuntimeException(e); // TODO(Sahoo): Proper Exception Handling } catch (ExecutionException e) {