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) {