bug 360671: associate synthetic context bundle where appropriate with BundleThreadContextManager
diff --git a/org.eclipse.virgo.kernel.deployer.test/src/test/java/org/eclipse/virgo/kernel/deployer/test/SyntheticContextTCCLIntegrationTests.java b/org.eclipse.virgo.kernel.deployer.test/src/test/java/org/eclipse/virgo/kernel/deployer/test/SyntheticContextTCCLIntegrationTests.java index 656c657..064767b 100644 --- a/org.eclipse.virgo.kernel.deployer.test/src/test/java/org/eclipse/virgo/kernel/deployer/test/SyntheticContextTCCLIntegrationTests.java +++ b/org.eclipse.virgo.kernel.deployer.test/src/test/java/org/eclipse/virgo/kernel/deployer/test/SyntheticContextTCCLIntegrationTests.java
@@ -14,7 +14,6 @@ import java.io.File; import org.eclipse.virgo.kernel.deployer.core.DeploymentIdentity; -import org.junit.Ignore; import org.junit.Test; /** @@ -29,7 +28,6 @@ * For the source of the PAR and "global" bundle, see test-apps/synthetic-tccl. Instructions for building are in * README.TXT. */ -@Ignore("Bug 360671 - Synthetic context class loader is not set as TCCL") public class SyntheticContextTCCLIntegrationTests extends AbstractDeployerIntegrationTest { @Test
diff --git a/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/BundleThreadContextManager.java b/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/BundleThreadContextManager.java index 21c794d..b90b37c 100644 --- a/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/BundleThreadContextManager.java +++ b/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/BundleThreadContextManager.java
@@ -43,7 +43,7 @@ private final OsgiFramework osgi; - private final Bundle contextBundle; + private final Bundle threadContextBundle; private final String scopeName; @@ -65,10 +65,16 @@ } }; - public BundleThreadContextManager(@NonNull OsgiFramework osgi, @NonNull Bundle contextBundle, String scopeName, + /** + * @param osgi + * @param threadContextBundle the bundle whose class loader is to be used as a TCCL + * @param scopeName + * @param tracingService + */ + public BundleThreadContextManager(@NonNull OsgiFramework osgi, @NonNull Bundle threadContextBundle, String scopeName, @NonNull TracingService tracingService) { this.osgi = osgi; - this.contextBundle = contextBundle; + this.threadContextBundle = threadContextBundle; this.scopeName = scopeName; this.tracingService = tracingService; } @@ -101,12 +107,12 @@ ClassLoader oldContextClassLoader = currentThread.getContextClassLoader(); this.contextClassLoaderStack.get().push(oldContextClassLoader); - int state = this.contextBundle.getState(); + int state = this.threadContextBundle.getState(); if (state != Bundle.INSTALLED && state != Bundle.UNINSTALLED) { ClassLoader newContextClassLoader = null; try { - newContextClassLoader = this.osgi.getBundleClassLoader(this.contextBundle); + newContextClassLoader = this.osgi.getBundleClassLoader(this.threadContextBundle); } catch (BundleClassLoaderUnavailableException _) { this.logger.info("Bundle class loader not available, it may not be resolved"); } @@ -114,7 +120,7 @@ currentThread.setContextClassLoader(newContextClassLoader); this.logger.info("Thread context class loader '{}' pushed and set to '{}'", oldContextClassLoader, newContextClassLoader); } else { - this.logger.info("Thread context class loader not found for bundle '{}'", this.contextBundle.getSymbolicName()); + this.logger.info("Thread context class loader not found for bundle '{}'", this.threadContextBundle.getSymbolicName()); } } }
diff --git a/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/StandardBundleDriver.java b/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/StandardBundleDriver.java index dfb5fe1..fba0418 100644 --- a/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/StandardBundleDriver.java +++ b/org.eclipse.virgo.kernel.deployer/src/main/java/org/eclipse/virgo/kernel/install/artifact/internal/bundle/StandardBundleDriver.java
@@ -11,14 +11,6 @@ package org.eclipse.virgo.kernel.install.artifact.internal.bundle; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.BundleListener; - -import org.eclipse.virgo.kernel.osgi.framework.OsgiFramework; -import org.eclipse.virgo.kernel.osgi.framework.PackageAdminUtil; - import org.eclipse.virgo.kernel.core.AbortableSignal; import org.eclipse.virgo.kernel.core.BundleStarter; import org.eclipse.virgo.kernel.core.BundleUtils; @@ -26,10 +18,20 @@ import org.eclipse.virgo.kernel.core.Signal; import org.eclipse.virgo.kernel.deployer.core.DeploymentException; import org.eclipse.virgo.kernel.install.artifact.ArtifactState; +import org.eclipse.virgo.kernel.install.artifact.BundleInstallArtifact; +import org.eclipse.virgo.kernel.install.artifact.InstallArtifact; +import org.eclipse.virgo.kernel.install.artifact.PlanInstallArtifact; import org.eclipse.virgo.kernel.install.artifact.internal.ArtifactStateMonitor; +import org.eclipse.virgo.kernel.osgi.framework.OsgiFramework; +import org.eclipse.virgo.kernel.osgi.framework.PackageAdminUtil; import org.eclipse.virgo.kernel.serviceability.Assert; import org.eclipse.virgo.kernel.shim.serviceability.TracingService; +import org.eclipse.virgo.util.common.Tree; import org.eclipse.virgo.util.osgi.manifest.BundleManifest; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.BundleListener; /** * {@link StandardBundleDriver} monitors the state of a bundle and keeps the associated {@link ArtifactState} up to @@ -43,39 +45,43 @@ */ final class StandardBundleDriver implements BundleDriver { + private static final String SYNTHETIC_CONTEXT_SUFFIX = "-synthetic.context"; + private final Object monitor = new Object(); private final BundleStarter bundleStarter; - + private final TracingService tracingService; private final PackageAdminUtil packageAdminUtil; - + private final BundleContext bundleContext; - + private final OsgiFramework osgi; - + private final ArtifactStateMonitor artifactStateMonitor; - + private volatile BundleThreadContextManager threadContextManager; private volatile StandardBundleInstallArtifact installArtifact; - + private volatile BundleDriverBundleListener bundleListener; - + private Bundle bundle; - + private final String applicationTraceName; - + /** * Creates a {@link StandardBundleDriver} for the given {@link Bundle} and {@link ArtifactState}. + * * @param osgiFramework framework * @param bundleContext context * @param bundleStarter to start bundles * @param tracingService to trace bundle operations * @param packageAdminUtil utilities for package administration */ - StandardBundleDriver(OsgiFramework osgiFramework, BundleContext bundleContext, BundleStarter bundleStarter, TracingService tracingService, PackageAdminUtil packageAdminUtil, String scopeName, ArtifactStateMonitor artifactStateMonitor) { + StandardBundleDriver(OsgiFramework osgiFramework, BundleContext bundleContext, BundleStarter bundleStarter, TracingService tracingService, + PackageAdminUtil packageAdminUtil, String scopeName, ArtifactStateMonitor artifactStateMonitor) { this.osgi = osgiFramework; this.bundleContext = bundleContext; this.tracingService = tracingService; @@ -91,17 +97,17 @@ public void setBundle(Bundle bundle) { BundleListener bundleListener = null; - + synchronized (this.monitor) { - if (this.bundle == null) { + if (getThreadContextBundle() == null) { this.bundle = bundle; - if (this.bundle != null) { - this.bundleListener = new BundleDriverBundleListener(this.installArtifact, this.bundle, this.artifactStateMonitor); + if (getThreadContextBundle() != null) { + this.bundleListener = new BundleDriverBundleListener(this.installArtifact, getThreadContextBundle(), this.artifactStateMonitor); bundleListener = this.bundleListener; } } } - + if (bundleListener != null) { this.bundleContext.addBundleListener(bundleListener); } @@ -133,10 +139,37 @@ private void ensureThreadContextManager() { synchronized (this.monitor) { if (this.threadContextManager == null) { - this.threadContextManager = new BundleThreadContextManager(this.osgi, this.bundle, this.applicationTraceName, this.tracingService); + this.threadContextManager = new BundleThreadContextManager(this.osgi, getThreadContextBundle(), this.applicationTraceName, + this.tracingService); } } - } + } + + private Bundle getThreadContextBundle() { + if (this.installArtifact != null) { + Tree<InstallArtifact> tree = this.installArtifact.getTree(); + Tree<InstallArtifact> parent = tree.getParent(); + while (parent != null) { + InstallArtifact parentArtifact = parent.getValue(); + if (parentArtifact instanceof PlanInstallArtifact) { + PlanInstallArtifact parentPlan = (PlanInstallArtifact) (parentArtifact); + if (parentPlan.isScoped()) { + String syntheticContextBundleSymbolicName = parentPlan.getScopeName() + SYNTHETIC_CONTEXT_SUFFIX; + for (Tree<InstallArtifact> scopedPlanChild : parent.getChildren()) { + InstallArtifact scopedPlanChildArtifact = scopedPlanChild.getValue(); + if (scopedPlanChildArtifact instanceof BundleInstallArtifact + && syntheticContextBundleSymbolicName.equals(scopedPlanChildArtifact.getName())) { + BundleInstallArtifact syntheticContextBundleArtifact = (BundleInstallArtifact) scopedPlanChildArtifact; + return syntheticContextBundleArtifact.getBundle(); + } + } + } + } + parent = parent.getParent(); + } + } + return this.bundle; + } /** * {@inheritDoc} @@ -179,13 +212,13 @@ signal.signalFailure(e); } } - + private static void signalSuccessfulCompletion(Signal signal) { if (signal != null) { signal.signalSuccessfulCompletion(); } } - + public void syncStart(int options) throws KernelException { Bundle bundle = obtainLocalBundle(); @@ -203,10 +236,10 @@ private Bundle obtainLocalBundle() { synchronized (this.monitor) { - if (this.bundle == null) { + if (getThreadContextBundle() == null) { throw new IllegalStateException("bundle not set"); } - return this.bundle; + return getThreadContextBundle(); } } @@ -263,7 +296,7 @@ */ public void uninstall() throws DeploymentException { Bundle bundle = obtainLocalBundle(); - + pushThreadContext(); try { bundle.uninstall(); @@ -272,18 +305,18 @@ } finally { popThreadContext(); } - + BundleListener localBundleListener = this.bundleListener; this.bundleListener = null; - + if (localBundleListener != null) { this.bundleContext.removeBundleListener(localBundleListener); } - - this.packageAdminUtil.synchronouslyRefreshPackages(new Bundle[] {bundle}); + + this.packageAdminUtil.synchronouslyRefreshPackages(new Bundle[] { bundle }); } - /** + /** * {@inheritDoc} */ public void trackStart(AbortableSignal signal) {