diff options
author | Thomas Watson | 2009-09-08 19:13:50 +0000 |
---|---|---|
committer | Thomas Watson | 2009-09-08 19:13:50 +0000 |
commit | 1320f1b9fbe5699dd30300f55737d26731035e5a (patch) | |
tree | 932c909006ec278f8561a81263f1db9288cc9c82 | |
parent | bb286f21405f581d54c70c5f7bd1d55352086d5a (diff) | |
download | rt.equinox.framework-1320f1b9fbe5699dd30300f55737d26731035e5a.tar.gz rt.equinox.framework-1320f1b9fbe5699dd30300f55737d26731035e5a.tar.xz rt.equinox.framework-1320f1b9fbe5699dd30300f55737d26731035e5a.zip |
Bug 288680 - Change lazy start trigger to be a one time event per class loader
6 files changed, 69 insertions, 37 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ClassLoadingBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ClassLoadingBundleTests.java index 5bcbdfec5..5a00f9807 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ClassLoadingBundleTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ClassLoadingBundleTests.java @@ -348,14 +348,20 @@ public class ClassLoadingBundleTests extends AbstractBundleTests { actualFrameworkEvents = frameworkListenerResults.getResults(1); compareResults(expectedFrameworkEvents, actualFrameworkEvents); + expectedEvents = new Object[1]; + expectedEvents[0] = new BundleEvent(BundleEvent.STARTED, osgiA); + actualEvents = simpleResults.getResults(1); + compareResults(expectedEvents, actualEvents); + startLevel.setStartLevel(startLevel.getStartLevel() - 15); expectedFrameworkEvents = new Object[1]; expectedFrameworkEvents[0] = new FrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, OSGiTestsActivator.getContext().getBundle(0), null); actualFrameworkEvents = frameworkListenerResults.getResults(1); compareResults(expectedFrameworkEvents, actualFrameworkEvents); - expectedEvents = new Object[0]; - actualEvents = simpleResults.getResults(0); + expectedEvents = new Object[1]; + expectedEvents[0] = new BundleEvent(BundleEvent.STOPPED, osgiA); + actualEvents = simpleResults.getResults(1); compareResults(expectedEvents, actualEvents); // now load a class while start-level is met. diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java index c7b6c957b..997cadc72 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/ClassLoaderDelegate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2005 IBM Corporation and others. + * Copyright (c) 2004, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -14,6 +14,7 @@ package org.eclipse.osgi.framework.adaptor; import java.io.IOException; import java.net.URL; import java.util.Enumeration; +import org.osgi.framework.BundleException; /** * A ClassLoaderDelegate is used by the BundleClassLoader in a similar @@ -25,6 +26,7 @@ import java.util.Enumeration; * <p> * This interface is not intended to be implemented by clients. * </p> + * @noimplement This interface is not intended to be implemented by clients. * @since 3.1 */ public interface ClassLoaderDelegate { @@ -89,4 +91,22 @@ public interface ClassLoaderDelegate { */ public String findLibrary(String libraryname); + /** + * Returns true if the lazy trigger has been set for this + * delegate. The lazy trigger is set when a bundle has been + * marked for lazy activation due to a successful class load. + * @return true if the lazy trigger has been set + * @since 3.6 + */ + public boolean isLazyTriggerSet(); + + /** + * Sets the lazy trigger for this delegate. This will activate + * the bundle if the bundle has been started with the activation + * policy and the bundle's start level is met. + * @throws BundleException if an error occurred while activating the bundle + * @see ClassLoaderDelegate#isLazyTriggerSet() + * @since 3.6 + */ + public void setLazyTrigger() throws BundleException; } diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java index 15c6114f4..323e52e13 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java @@ -24,6 +24,7 @@ import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; public class BundleHost extends AbstractBundle { + public static final int LAZY_TRIGGER = 0x40000000; /** * The BundleLoader proxy; a lightweight object that acts as a proxy * to the BundleLoader and allows lazy creation of the BundleLoader object @@ -235,7 +236,7 @@ public class BundleHost extends AbstractBundle { if (!(e instanceof StatusException) && (bundledata.getStatus() & Constants.BUNDLE_LAZY_START) != 0 && !testStateChanging(Thread.currentThread())) try { // only start the bundle if this is a simple CNFE - framework.secureAction.start(this, START_TRANSIENT); + loader.setLazyTrigger(); } catch (BundleException be) { framework.adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, be.getMessage(), 0, be, null)); } @@ -303,9 +304,8 @@ public class BundleHost extends AbstractBundle { } if (!framework.active || (state & ACTIVE) != 0) return; - if (getStartLevel() > framework.startLevelManager.getStartLevel()) { - if ((options & START_TRANSIENT) != 0) { + if ((options & LAZY_TRIGGER) == 0 && (options & START_TRANSIENT) != 0) { // throw exception if this is a transient start String msg = NLS.bind(Msg.BUNDLE_TRANSIENT_START_ERROR, this); // Use a StatusException to indicate to the lazy starter that this should result in a warning @@ -409,11 +409,13 @@ public class BundleHost extends AbstractBundle { // Return false if the bundle is not persistently marked for start if ((status & Constants.BUNDLE_STARTED) == 0) return false; - if ((status & Constants.BUNDLE_ACTIVATION_POLICY) == 0 || (status & Constants.BUNDLE_LAZY_START) == 0) + if ((status & Constants.BUNDLE_ACTIVATION_POLICY) == 0 || (status & Constants.BUNDLE_LAZY_START) == 0 || isLazyTriggerSet()) return true; - if (!isResolved()) - // should never transition from UNRESOLVED -> STARTING - return false; + if (!isResolved()) { + if (framework.getAdaptor().getState().isResolved() || !framework.packageAdmin.resolveBundles(new Bundle[] {this})) + // should never transition from UNRESOLVED -> STARTING + return false; + } // now we can publish the LAZY_ACTIVATION event state = STARTING; // release the state change lock before sending lazy activation event (bug 258659) @@ -422,6 +424,13 @@ public class BundleHost extends AbstractBundle { return false; } + private synchronized boolean isLazyTriggerSet() { + if (proxy == null) + return false; + BundleLoader loader = proxy.getBasicBundleLoader(); + return loader != null ? loader.isLazyTriggerSet() : false; + } + /** * Create a BundleContext for this bundle. * diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java index 2836cfc13..a26ec7177 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java @@ -46,7 +46,6 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL /** An object used to lock the active startlevel while it is being referenced */ private final Object lock = new Object(); private final Framework framework; - volatile private boolean settingStartLevel = false; /** This constructor is called by the Framework */ protected StartLevelManager(Framework framework) { @@ -224,7 +223,6 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL */ void doSetStartLevel(int newSL) { synchronized (lock) { - settingStartLevel = true; ClassLoader previousTCCL = Thread.currentThread().getContextClassLoader(); ClassLoader contextFinder = framework.getContextFinder(); if (contextFinder == previousTCCL) @@ -273,7 +271,6 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL } finally { if (contextFinder != null) Thread.currentThread().setContextClassLoader(previousTCCL); - settingStartLevel = false; } } } @@ -696,8 +693,4 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL } } } - - public boolean isSettingStartLevel() { - return settingStartLevel; - } } diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/loader/BundleLoader.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/loader/BundleLoader.java index ae867f25f..bdc87209c 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/loader/BundleLoader.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/loader/BundleLoader.java @@ -20,12 +20,12 @@ import java.util.*; import org.eclipse.osgi.framework.adaptor.*; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.framework.internal.core.Constants; import org.eclipse.osgi.framework.util.KeyedHashSet; import org.eclipse.osgi.internal.loader.buddy.PolicyHandler; import org.eclipse.osgi.service.resolver.*; import org.eclipse.osgi.util.ManifestElement; -import org.osgi.framework.BundleException; -import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.*; /** * This object is responsible for all classloader delegation for a bundle. @@ -41,6 +41,7 @@ public class BundleLoader implements ClassLoaderDelegate { public final static byte FLAG_HASDYNAMICIMPORTS = 0x02; public final static byte FLAG_HASDYNAMICEIMPORTALL = 0x04; public final static byte FLAG_CLOSED = 0x08; + public final static byte FLAG_LAZYTRIGGER = 0x10; public final static ClassContext CLASS_CONTEXT = (ClassContext) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { @@ -253,6 +254,17 @@ public class BundleLoader implements ClassLoaderDelegate { return importedSources; } + public synchronized boolean isLazyTriggerSet() { + return (loaderFlags & FLAG_LAZYTRIGGER) != 0; + } + + public void setLazyTrigger() throws BundleException { + synchronized (this) { + loaderFlags |= FLAG_LAZYTRIGGER; + } + BundleLoaderProxy.secureAction.start(bundle, Bundle.START_TRANSIENT | BundleHost.LAZY_TRIGGER); + } + final PackageSource createExportPackageSource(ExportPackageDescription export, KeyedHashSet visited) { BundleLoaderProxy exportProxy = getLoaderProxy(export.getExporter()); if (exportProxy == null) diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java index 75fefdbca..d9a4df652 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. + * Copyright (c) 2006, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -14,7 +14,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.io.IOException; import java.net.URL; import java.net.URLConnection; -import java.security.AccessController; import java.util.*; import org.eclipse.osgi.baseadaptor.*; import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; @@ -26,20 +25,16 @@ import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; import org.eclipse.osgi.framework.adaptor.StatusException; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.framework.internal.core.Constants; import org.eclipse.osgi.framework.log.FrameworkLog; import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.framework.util.SecureAction; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.StateHelper; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; -import org.osgi.service.startlevel.StartLevel; public class EclipseLazyStarter implements ClassLoadingStatsHook, AdaptorHook, HookConfigurator { private static final boolean throwErrorOnFailedStart = "true".equals(FrameworkProperties.getProperty("osgi.compatibility.errorOnFailedStart", "true")); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - private static final SecureAction secureAction = (SecureAction) AccessController.doPrivileged(SecureAction.createSecureAction()); - private StartLevelManager startLevelService; - private ServiceReference slRef; private BaseAdaptor adaptor; // holds the current activation trigger class and the ClasspathManagers that need to be activated private ThreadLocal activationStack = new ThreadLocal(); @@ -102,14 +97,15 @@ public class EclipseLazyStarter implements ClassLoadingStatsHook, AdaptorHook, H throw (TerminatingClassNotFoundException) errors.get(managers[i]); continue; } - AbstractBundle bundle = (AbstractBundle) managers[i].getBaseData().getBundle(); + // The bundle must be started. // Note that another thread may already be starting this bundle; // In this case we will timeout after 5 seconds and record the BundleException try { // do not persist the start of this bundle - secureAction.start(bundle, Bundle.START_TRANSIENT); + managers[i].getBaseClassLoader().getDelegate().setLazyTrigger(); } catch (BundleException e) { + Bundle bundle = managers[i].getBaseData().getBundle(); Throwable cause = e.getCause(); if (cause != null && cause instanceof StatusException) { StatusException status = (StatusException) cause; @@ -148,6 +144,8 @@ public class EclipseLazyStarter implements ClassLoadingStatsHook, AdaptorHook, H private boolean shouldActivateFor(String className, BaseData bundledata, EclipseStorageHook storageHook, ClasspathManager manager) throws ClassNotFoundException { if (!isLazyStartable(className, bundledata, storageHook)) return false; + //if (manager.getBaseClassLoader().getDelegate().isLazyTriggerSet()) + // return false; // Don't activate non-starting bundles if (bundledata.getBundle().getState() == Bundle.RESOLVED) { if (throwErrorOnFailedStart) { @@ -155,8 +153,7 @@ public class EclipseLazyStarter implements ClassLoadingStatsHook, AdaptorHook, H if (error != null) throw error; } - StartLevelManager sl = startLevelService; - return sl != null && ((sl.getStartLevel() == bundledata.getStartLevel() && sl.isSettingStartLevel())); + return (bundledata.getStatus() & Constants.BUNDLE_STARTED) != 0; } return true; } @@ -203,16 +200,11 @@ public class EclipseLazyStarter implements ClassLoadingStatsHook, AdaptorHook, H } public void frameworkStart(BundleContext context) throws BundleException { - slRef = context.getServiceReference(StartLevel.class.getName()); - if (slRef != null) - startLevelService = (StartLevelManager) context.getService(slRef); + // nothing } public void frameworkStop(BundleContext context) throws BundleException { - if (slRef != null) { - context.ungetService(slRef); - startLevelService = null; - } + // nothing } public void frameworkStopping(BundleContext context) { |