blob: 96e0c20929c54e94308f400324b4776a2ecbf237 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2010 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.core;
import java.io.IOException;
import java.security.*;
import java.util.*;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.framework.eventmgr.*;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.service.startlevel.StartLevel;
/**
* StartLevel service implementation for the OSGi specification.
*
* Framework service which allows management of framework and bundle startlevels.
*
* This class also acts as the StartLevel service factory class, providing StartLevel objects
* to those requesting org.osgi.service.startlevel.StartLevel service.
*
* If present, there will only be a single instance of this service
* registered in the framework.
*/
public class StartLevelManager implements EventDispatcher, EventListener, StartLevel {
protected static EventManager eventManager;
protected static Map startLevelListeners;
/** The initial bundle start level for newly installed bundles */
protected int initialBundleStartLevel = 1;
// default value is 1 for compatibility mode
/** The currently active framework start level */
private int activeSL = 0;
/** An object used to lock the active startlevel while it is being referenced */
private final Object lock = new Object();
private final Framework framework;
/** This constructor is called by the Framework */
protected StartLevelManager(Framework framework) {
this.framework = framework;
}
protected void initialize() {
initialBundleStartLevel = framework.adaptor.getInitialBundleStartLevel();
// create an event manager and a start level listener
// note that we do not pass the ContextFinder because it is set each time doSetStartLevel is called
eventManager = new EventManager("Start Level Event Dispatcher"); //$NON-NLS-1$
startLevelListeners = new CopyOnWriteIdentityMap();
startLevelListeners.put(this, this);
}
protected void cleanup() {
eventManager.close();
eventManager = null;
startLevelListeners.clear();
startLevelListeners = null;
}
/**
* Return the initial start level value that is assigned
* to a Bundle when it is first installed.
*
* @return The initial start level value for Bundles.
* @see #setInitialBundleStartLevel
*/
public int getInitialBundleStartLevel() {
return initialBundleStartLevel;
}
/**
* Set the initial start level value that is assigned
* to a Bundle when it is first installed.
*
* <p>The initial bundle start level will be set to the specified start level. The
* initial bundle start level value will be persistently recorded
* by the Framework.
*
* <p>When a Bundle is installed via <tt>BundleContext.installBundle</tt>,
* it is assigned the initial bundle start level value.
*
* <p>The default initial bundle start level value is 1
* unless this method has been
* called to assign a different initial bundle
* start level value.
*
* <p>This method does not change the start level values of installed
* bundles.
*
* @param startlevel The initial start level for newly installed bundles.
* @throws IllegalArgumentException If the specified start level is less than or
* equal to zero.
* @throws SecurityException if the caller does not have the
* <tt>AdminPermission</tt> and the Java runtime environment supports
* permissions.
*/
public void setInitialBundleStartLevel(int startlevel) {
framework.checkAdminPermission(framework.systemBundle, AdminPermission.STARTLEVEL);
if (startlevel <= 0) {
throw new IllegalArgumentException();
}
initialBundleStartLevel = startlevel;
framework.adaptor.setInitialBundleStartLevel(startlevel);
}
/**
* Return the active start level value of the Framework.
*
* If the Framework is in the process of changing the start level
* this method must return the active start level if this
* differs from the requested start level.
*
* @return The active start level value of the Framework.
*/
public int getStartLevel() {
return activeSL;
}
/**
* Modify the active start level of the Framework.
*
* <p>The Framework will move to the requested start level. This method
* will return immediately to the caller and the start level
* change will occur asynchronously on another thread.
*
* <p>If the specified start level is
* higher than the active start level, the
* Framework will continue to increase the start level
* until the Framework has reached the specified start level,
* starting bundles at each
* start level which are persistently marked to be started as described in the
* <tt>Bundle.start</tt> method.
*
* At each intermediate start level value on the
* way to and including the target start level, the framework must:
* <ol>
* <li>Change the active start level to the intermediate start level value.
* <li>Start bundles at the intermediate start level in
* ascending order by <tt>Bundle.getBundleId</tt>.
* </ol>
* When this process completes after the specified start level is reached,
* the Framework will broadcast a Framework event of
* type <tt>FrameworkEvent.STARTLEVEL_CHANGED</tt> to announce it has moved to the specified
* start level.
*
* <p>If the specified start level is lower than the active start level, the
* Framework will continue to decrease the start level
* until the Framework has reached the specified start level
* stopping bundles at each
* start level as described in the <tt>Bundle.stop</tt> method except that their
* persistently recorded state indicates that they must be restarted in the
* future.
*
* At each intermediate start level value on the
* way to and including the specified start level, the framework must:
* <ol>
* <li>Stop bundles at the intermediate start level in
* descending order by <tt>Bundle.getBundleId</tt>.
* <li>Change the active start level to the intermediate start level value.
* </ol>
* When this process completes after the specified start level is reached,
* the Framework will broadcast a Framework event of
* type <tt>FrameworkEvent.STARTLEVEL_CHANGED</tt> to announce it has moved to the specified
* start level.
*
* <p>If the specified start level is equal to the active start level, then
* no bundles are started or stopped, however, the Framework must broadcast
* a Framework event of type <tt>FrameworkEvent.STARTLEVEL_CHANGED</tt> to
* announce it has finished moving to the specified start level. This
* event may arrive before the this method return.
*
* @param newSL The requested start level for the Framework.
* @throws IllegalArgumentException If the specified start level is less than or
* equal to zero.
* @throws SecurityException If the caller does not have the
* <tt>AdminPermission</tt> and the Java runtime environment supports
* permissions.
*/
public void setStartLevel(int newSL, org.osgi.framework.Bundle callerBundle) {
if (newSL <= 0) {
throw new IllegalArgumentException(NLS.bind(Msg.STARTLEVEL_EXCEPTION_INVALID_REQUESTED_STARTLEVEL, "" + newSL)); //$NON-NLS-1$
}
framework.checkAdminPermission(framework.systemBundle, AdminPermission.STARTLEVEL);
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("StartLevelImpl: setStartLevel: " + newSL + "; callerBundle = " + callerBundle.getBundleId()); //$NON-NLS-1$ //$NON-NLS-2$
}
issueEvent(new StartLevelEvent(StartLevelEvent.CHANGE_FW_SL, newSL, (AbstractBundle) callerBundle));
}
public void setStartLevel(int newSL) {
setStartLevel(newSL, framework.systemBundle);
}
/**
* Internal method to shut down the framework synchronously by setting the startlevel to zero
* and calling the StartLevelListener worker calls directly
*
* This method does not return until all bundles are stopped and the framework is shut down.
*/
protected void shutdown() {
doSetStartLevel(0);
}
/**
* Internal worker method to set the startlevel
*
* @param newSL start level value
* @param callerBundle - the bundle initiating the change in start level
*/
void doSetStartLevel(int newSL) {
synchronized (lock) {
ClassLoader previousTCCL = Thread.currentThread().getContextClassLoader();
ClassLoader contextFinder = framework.getContextFinder();
if (contextFinder == previousTCCL)
contextFinder = null;
else
Thread.currentThread().setContextClassLoader(contextFinder);
try {
int tempSL = activeSL;
if (newSL > tempSL) {
boolean launching = tempSL == 0;
for (int i = tempSL; i < newSL; i++) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("sync - incrementing Startlevel from " + tempSL); //$NON-NLS-1$
}
tempSL++;
// Note that we must get a new list of installed bundles each time;
// this is because additional bundles could have been installed from the previous start-level
incFWSL(i + 1, getInstalledBundles(framework.bundles, false));
}
if (launching) {
framework.systemBundle.state = Bundle.ACTIVE;
framework.publishBundleEvent(BundleEvent.STARTED, framework.systemBundle);
framework.publishFrameworkEvent(FrameworkEvent.STARTED, framework.systemBundle, null);
}
} else {
AbstractBundle[] sortedBundles = getInstalledBundles(framework.bundles, true);
for (int i = tempSL; i > newSL; i--) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("sync - decrementing Startlevel from " + tempSL); //$NON-NLS-1$
}
tempSL--;
decFWSL(i - 1, sortedBundles);
}
if (newSL == 0) {
// stop and unload all bundles
suspendAllBundles(framework.bundles);
unloadAllBundles(framework.bundles);
}
}
framework.publishFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, framework.systemBundle, null);
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("StartLevelImpl: doSetStartLevel: STARTLEVEL_CHANGED event published"); //$NON-NLS-1$
}
} finally {
if (contextFinder != null)
Thread.currentThread().setContextClassLoader(previousTCCL);
}
}
}
/**
* This method is used within the package to save the actual active startlevel value for the framework.
* Externally the setStartLevel method must be used.
*
* @param newSL - the new startlevel to save
*/
protected void saveActiveStartLevel(int newSL) {
synchronized (lock) {
activeSL = newSL;
}
}
/**
* Return the persistent state of the specified bundle.
*
* <p>This method returns the persistent state of a bundle.
* The persistent state of a bundle indicates whether a bundle
* is persistently marked to be started when it's start level is
* reached.
*
* @return <tt>true</tt> if the bundle is persistently marked to be started,
* <tt>false</tt> if the bundle is not persistently marked to be started.
* @exception java.lang.IllegalArgumentException If the specified bundle has been uninstalled.
*/
public boolean isBundlePersistentlyStarted(org.osgi.framework.Bundle bundle) {
if (bundle.getState() == Bundle.UNINSTALLED)
throw new IllegalArgumentException(NLS.bind(Msg.BUNDLE_UNINSTALLED_EXCEPTION, ((AbstractBundle) bundle).getBundleData().getLocation()));
return (((AbstractBundle) bundle).getBundleData().getStatus() & Constants.BUNDLE_STARTED) != 0;
}
public boolean isBundleActivationPolicyUsed(Bundle bundle) {
if (bundle.getState() == Bundle.UNINSTALLED)
throw new IllegalArgumentException(NLS.bind(Msg.BUNDLE_UNINSTALLED_EXCEPTION, ((AbstractBundle) bundle).getBundleData().getLocation()));
return (((AbstractBundle) bundle).getBundleData().getStatus() & Constants.BUNDLE_ACTIVATION_POLICY) != 0;
}
/**
* Return the assigned start level value for the specified Bundle.
*
* @param bundle The target bundle.
* @return The start level value of the specified Bundle.
* @exception java.lang.IllegalArgumentException If the specified bundle has been uninstalled.
*/
public int getBundleStartLevel(org.osgi.framework.Bundle bundle) {
if (bundle.getState() == Bundle.UNINSTALLED) {
throw new IllegalArgumentException(NLS.bind(Msg.BUNDLE_UNINSTALLED_EXCEPTION, ((AbstractBundle) bundle).getBundleData().getLocation()));
}
return ((AbstractBundle) bundle).getStartLevel();
}
/**
* Assign a start level value to the specified Bundle.
*
* <p>The specified bundle will be assigned the specified start level. The
* start level value assigned to the bundle will be persistently recorded
* by the Framework.
*
* If the new start level for the bundle is lower than or equal to the active start level of
* the Framework, the Framework will start the specified bundle as described
* in the <tt>Bundle.start</tt> method if the bundle is persistently marked
* to be started. The actual starting of this bundle must occur asynchronously.
*
* If the new start level for the bundle is higher than the active start level of
* the Framework, the Framework will stop the specified bundle as described
* in the <tt>Bundle.stop</tt> method except that the persistently recorded
* state for the bundle indicates that the bundle must be restarted in the
* future. The actual stopping of this bundle must occur asynchronously.
*
* @param bundle The target bundle.
* @param newSL The new start level for the specified Bundle.
* @throws IllegalArgumentException
* If the specified bundle has been uninstalled or
* if the specified start level is less than or equal to zero, or the specified bundle is
* the system bundle.
* @throws SecurityException if the caller does not have the
* <tt>AdminPermission</tt> and the Java runtime environment supports
* permissions.
*/
public void setBundleStartLevel(org.osgi.framework.Bundle bundle, int newSL) {
String exceptionText = null;
if (bundle.getBundleId() == 0) { // system bundle has id=0
exceptionText = Msg.STARTLEVEL_CANT_CHANGE_SYSTEMBUNDLE_STARTLEVEL;
} else if (bundle.getState() == Bundle.UNINSTALLED) {
exceptionText = NLS.bind(Msg.BUNDLE_UNINSTALLED_EXCEPTION, ((AbstractBundle) bundle).getBundleData().getLocation());
} else if (newSL <= 0) {
exceptionText = NLS.bind(Msg.STARTLEVEL_EXCEPTION_INVALID_REQUESTED_STARTLEVEL, "" + newSL); //$NON-NLS-1$
}
if (exceptionText != null)
throw new IllegalArgumentException(exceptionText);
// first check the permission of the caller
framework.checkAdminPermission(bundle, AdminPermission.EXECUTE);
try {
// if the bundle's startlevel is not already at the requested startlevel
if (newSL != ((org.eclipse.osgi.framework.internal.core.AbstractBundle) bundle).getStartLevel()) {
final AbstractBundle b = (AbstractBundle) bundle;
b.getBundleData().setStartLevel(newSL);
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
b.getBundleData().save();
return null;
}
});
} catch (PrivilegedActionException e) {
if (e.getException() instanceof IOException) {
throw (IOException) e.getException();
}
throw (RuntimeException) e.getException();
}
// handle starting or stopping the bundle asynchronously
issueEvent(new StartLevelEvent(StartLevelEvent.CHANGE_BUNDLE_SL, newSL, (AbstractBundle) bundle));
}
} catch (IOException e) {
framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, e);
}
}
/**
* This method sends the StartLevelEvent to the EventManager for dispatching
*
* @param sle The event to be queued to the Event Manager
*/
private void issueEvent(StartLevelEvent sle) {
/* queue to hold set of listeners */
ListenerQueue queue = new ListenerQueue(eventManager);
/* add set of StartLevelListeners to queue */
queue.queueListeners(startLevelListeners.entrySet(), this);
/* dispatch event to set of listeners */
queue.dispatchEventAsynchronous(sle.getType(), sle);
}
/**
* This method is the call back that is called once for each listener.
* This method must cast the EventListener object to the appropriate listener
* class for the event type and call the appropriate listener method.
*
* @param listener This listener must be cast to the appropriate listener
* class for the events created by this source and the appropriate listener method
* must then be called.
* @param listenerObject This is the optional object that was passed to
* EventListeners.addListener when the listener was added to the EventListeners.
* @param eventAction This value was passed to the ListenerQueue object via one of its
* dispatchEvent* method calls. It can provide information (such
* as which listener method to call) so that this method
* can complete the delivery of the event to the listener.
* @param eventObject This object was passed to the ListenerQueue object via one of its
* dispatchEvent* method calls. This object was created by the event source and
* is passed to this method. It should contain all the necessary information (such
* as what event object to pass) so that this method
* can complete the delivery of the event to the listener.
*/
public void dispatchEvent(Object listener, Object listenerObject, int eventAction, Object eventObject) {
try {
switch (eventAction) {
case StartLevelEvent.CHANGE_BUNDLE_SL :
setBundleSL((StartLevelEvent) eventObject);
break;
case StartLevelEvent.CHANGE_FW_SL :
doSetStartLevel(((StartLevelEvent) eventObject).getNewSL());
break;
}
} catch (Throwable t) {
// allow the adaptor to handle this unexpected error
framework.adaptor.handleRuntimeError(t);
}
}
/**
* Increment the active startlevel by one
*/
protected void incFWSL(int incToSL, AbstractBundle[] launchBundles) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: incFWSL: saving activeSL of " + incToSL); //$NON-NLS-1$
}
// save the startlevel
saveActiveStartLevel(incToSL);
// resume all bundles at the startlevel
resumeBundles(launchBundles, incToSL);
}
/**
* Build an array of all installed bundles to be launch.
* The returned array is sorted by increasing startlevel/id order.
* @param bundles - the bundles installed in the framework
* @return A sorted array of bundles
*/
AbstractBundle[] getInstalledBundles(BundleRepository bundles, boolean sortByDependency) {
/* make copy of bundles vector in case it is modified during launch */
AbstractBundle[] installedBundles;
synchronized (bundles) {
List allBundles = bundles.getBundles();
installedBundles = new AbstractBundle[allBundles.size()];
allBundles.toArray(installedBundles);
/* sort bundle array in ascending startlevel / bundle id order
* so that bundles are started in ascending order.
*/
Util.sort(installedBundles, 0, installedBundles.length);
if (sortByDependency)
sortByDependency(installedBundles);
}
return installedBundles;
}
void sortByDependency(AbstractBundle[] bundles) {
synchronized (framework.bundles) {
if (bundles.length <= 1)
return;
int currentSL = bundles[0].getStartLevel();
int currentSLindex = 0;
boolean lazy = false;
for (int i = 0; i < bundles.length; i++) {
if (currentSL != bundles[i].getStartLevel()) {
if (lazy)
sortByDependencies(bundles, currentSLindex, i);
currentSL = bundles[i].getStartLevel();
currentSLindex = i;
lazy = false;
}
lazy |= (bundles[i].getBundleData().getStatus() & Constants.BUNDLE_LAZY_START) != 0;
}
// sort the last set of bundles
if (lazy)
sortByDependencies(bundles, currentSLindex, bundles.length);
}
}
private void sortByDependencies(AbstractBundle[] bundles, int start, int end) {
if (end - start <= 1)
return;
List descList = new ArrayList(end - start);
List missingDescs = new ArrayList(0);
for (int i = start; i < end; i++) {
BundleDescription desc = bundles[i].getBundleDescription();
if (desc != null)
descList.add(desc);
else
missingDescs.add(bundles[i]);
}
if (descList.size() <= 1)
return;
BundleDescription[] descriptions = (BundleDescription[]) descList.toArray(new BundleDescription[descList.size()]);
framework.adaptor.getPlatformAdmin().getStateHelper().sortBundles(descriptions);
for (int i = start; i < descriptions.length + start; i++)
bundles[i] = framework.bundles.getBundle(descriptions[i - start].getBundleId());
if (missingDescs.size() > 0) {
Iterator missing = missingDescs.iterator();
for (int i = start + descriptions.length; i < end && missing.hasNext(); i++)
bundles[i] = (AbstractBundle) missing.next();
}
}
/**
* Resume all bundles in the launch list at the specified start-level
* @param launch a list of Bundle Objects to launch
* @param currentSL the current start-level that the bundles must meet to be resumed
*/
private void resumeBundles(AbstractBundle[] launch, int currentSL) {
// Resume all bundles that were previously started and whose startlevel is <= the active startlevel
// first resume the lazy activated bundles
resumeBundles(launch, true, currentSL);
// now resume all non lazy bundles
resumeBundles(launch, false, currentSL);
}
private void resumeBundles(AbstractBundle[] launch, boolean lazyOnly, int currentSL) {
for (int i = 0; i < launch.length && !framework.isForcedRestart(); i++) {
int bsl = launch[i].getStartLevel();
if (bsl < currentSL) {
// skip bundles who should have already been started
continue;
} else if (bsl == currentSL) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: Active sl = " + currentSL + "; Bundle " + launch[i].getBundleId() + " sl = " + bsl); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
boolean isLazyStart = launch[i].isLazyStart();
if (lazyOnly ? isLazyStart : !isLazyStart)
framework.resumeBundle(launch[i]);
} else {
// can stop resuming bundles since any remaining bundles have a greater startlevel than the framework active startlevel
break;
}
}
}
/**
* Decrement the active startlevel by one
* @param decToSL - the startlevel value to set the framework to
*/
protected void decFWSL(int decToSL, AbstractBundle[] shutdown) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: decFWSL: saving activeSL of " + decToSL); //$NON-NLS-1$
}
saveActiveStartLevel(decToSL);
if (decToSL == 0) // stopping the framework
return;
// just decrementing the active startlevel - framework is not shutting down
// Do not check framework.isForcedRestart here because we want to stop the active bundles regardless.
for (int i = shutdown.length - 1; i >= 0; i--) {
int bsl = shutdown[i].getStartLevel();
if (bsl > decToSL + 1)
// skip bundles who should have already been stopped
continue;
else if (bsl <= decToSL)
// stopped all bundles we are going to for this start level
break;
else if (shutdown[i].isActive()) {
// if bundle is active or starting, then stop the bundle
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL)
Debug.println("SLL: stopping bundle " + shutdown[i].getBundleId()); //$NON-NLS-1$
framework.suspendBundle(shutdown[i], false);
}
}
}
/**
* Suspends all bundles in the vector passed in.
* @param bundles list of Bundle objects to be suspended
*/
private void suspendAllBundles(BundleRepository bundles) {
boolean changed;
do {
changed = false;
AbstractBundle[] shutdown = this.getInstalledBundles(bundles, false);
// shutdown all running bundles
for (int i = shutdown.length - 1; i >= 0; i--) {
AbstractBundle bundle = shutdown[i];
if (framework.suspendBundle(bundle, false)) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: stopped bundle " + bundle.getBundleId()); //$NON-NLS-1$
}
changed = true;
}
}
} while (changed);
try {
framework.systemBundle.context.stop();
} catch (BundleException sbe) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: Bundle suspend exception: " + sbe.getMessage()); //$NON-NLS-1$
Debug.printStackTrace(sbe.getNestedException() == null ? sbe : sbe.getNestedException());
}
framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, sbe);
}
framework.systemBundle.state = Bundle.RESOLVED;
framework.publishBundleEvent(BundleEvent.STOPPED, framework.systemBundle);
}
/**
* Unloads all bundles in the vector passed in.
* @param bundles list of Bundle objects to be unloaded
*/
private void unloadAllBundles(BundleRepository bundles) {
synchronized (bundles) {
/* unload all installed bundles */
List allBundles = bundles.getBundles();
int size = allBundles.size();
for (int i = 0; i < size; i++) {
AbstractBundle bundle = (AbstractBundle) allBundles.get(i);
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: Trying to unload bundle " + bundle); //$NON-NLS-1$
}
bundle.refresh();
try {
// make sure we close all the bundle data objects
bundle.getBundleData().close();
} catch (IOException e) {
// ignore, we are shutting down anyway
}
}
}
}
/**
* Set the bundle's startlevel to the new value
* This may cause the bundle to start or stop based on the active framework startlevel
* @param startLevelEvent - the event requesting change in bundle startlevel
*/
protected void setBundleSL(StartLevelEvent startLevelEvent) {
synchronized (lock) {
int currentSL = getStartLevel();
int newSL = startLevelEvent.getNewSL();
AbstractBundle bundle = startLevelEvent.getBundle();
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.print("SLL: bundle active=" + bundle.isActive()); //$NON-NLS-1$
Debug.print("; newSL = " + newSL); //$NON-NLS-1$
Debug.println("; activeSL = " + currentSL); //$NON-NLS-1$
}
if (bundle.isActive() && (newSL > currentSL)) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: stopping bundle " + bundle.getBundleId()); //$NON-NLS-1$
}
framework.suspendBundle(bundle, false);
} else {
if (!bundle.isActive() && (newSL <= currentSL)) {
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: starting bundle " + bundle.getBundleId()); //$NON-NLS-1$
}
framework.resumeBundle(bundle);
}
}
if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) {
Debug.println("SLL: Bundle Startlevel set to " + newSL); //$NON-NLS-1$
}
}
}
}