diff options
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/internal/core/StartLevelManager.java')
-rw-r--r-- | bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/internal/core/StartLevelManager.java | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/internal/core/StartLevelManager.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/internal/core/StartLevelManager.java new file mode 100644 index 000000000..efd697c99 --- /dev/null +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/internal/core/StartLevelManager.java @@ -0,0 +1,678 @@ +/******************************************************************************* + * Copyright (c) 2003, 2011 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<Object, Object, StartLevelEvent>, StartLevel { + protected static EventManager eventManager; + protected static Map<Object, Object> 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<Object, Object>(); + 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, FrameworkListener... listeners) { + 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_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, listeners)); + + } + + 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, FrameworkListener... listeners) { + 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_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_STARTLEVEL) { + Debug.println("sync - decrementing Startlevel from " + tempSL); //$NON-NLS-1$ + } + tempSL--; + decFWSL(i - 1, sortedBundles); + } + if (newSL == 0) { + // unload all bundles + unloadAllBundles(framework.bundles); + stopSystemBundle(); + } + } + framework.publishFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, framework.systemBundle, null, listeners); + if (Debug.DEBUG_STARTLEVEL) { + Debug.println("StartLevelImpl: doSetStartLevel: STARTLEVEL_CHANGED event published"); //$NON-NLS-1$ + } + } catch (Error e) { + framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e, listeners); + throw e; + } catch (RuntimeException e) { + framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e, listeners); + throw e; + } 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) { + return ((AbstractBundle) bundle).isPersistentlyStarted(); + } + + public boolean isBundleActivationPolicyUsed(Bundle bundle) { + return ((AbstractBundle) bundle).isActivationPolicyUsed(); + } + + /** + * 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) { + 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).getInternalStartLevel()) { + final AbstractBundle b = (AbstractBundle) bundle; + b.getBundleData().setStartLevel(newSL); + try { + AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { + 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<Object, Object, StartLevelEvent> queue = new ListenerQueue<Object, Object, StartLevelEvent>(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 event 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, StartLevelEvent event) { + try { + switch (eventAction) { + case StartLevelEvent.CHANGE_BUNDLE_SL : + setBundleSL(event); + break; + case StartLevelEvent.CHANGE_FW_SL : + doSetStartLevel(event.getNewSL(), event.getListeners()); + 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_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<AbstractBundle> 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].getInternalStartLevel(); + int currentSLindex = 0; + boolean lazy = false; + for (int i = 0; i < bundles.length; i++) { + if (currentSL != bundles[i].getInternalStartLevel()) { + if (lazy) + sortByDependencies(bundles, currentSLindex, i); + currentSL = bundles[i].getInternalStartLevel(); + 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<BundleDescription> descList = new ArrayList<BundleDescription>(end - start); + List<AbstractBundle> missingDescs = new ArrayList<AbstractBundle>(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 = 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<AbstractBundle> missing = missingDescs.iterator(); + for (int i = start + descriptions.length; i < end && missing.hasNext(); i++) + bundles[i] = 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].getInternalStartLevel(); + if (bsl < currentSL) { + // skip bundles who should have already been started + continue; + } else if (bsl == currentSL) { + if (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_STARTLEVEL) { + Debug.println("SLL: decFWSL: saving activeSL of " + decToSL); //$NON-NLS-1$ + } + + saveActiveStartLevel(decToSL); + + // 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].getInternalStartLevel(); + 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_STARTLEVEL) + Debug.println("SLL: stopping bundle " + shutdown[i].getBundleId()); //$NON-NLS-1$ + framework.suspendBundle(shutdown[i], false); + } + } + } + + /** + * Stops the system bundle + */ + private void stopSystemBundle() { + try { + framework.systemBundle.context.stop(); + } catch (BundleException sbe) { + if (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<AbstractBundle> allBundles = bundles.getBundles(); + int size = allBundles.size(); + + for (int i = 0; i < size; i++) { + AbstractBundle bundle = allBundles.get(i); + + if (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_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_STARTLEVEL) { + Debug.println("SLL: stopping bundle " + bundle.getBundleId()); //$NON-NLS-1$ + } + framework.suspendBundle(bundle, false); + } else { + if (!bundle.isActive() && (newSL <= currentSL)) { + if (Debug.DEBUG_STARTLEVEL) { + Debug.println("SLL: starting bundle " + bundle.getBundleId()); //$NON-NLS-1$ + } + framework.resumeBundle(bundle); + } + } + if (Debug.DEBUG_STARTLEVEL) { + Debug.println("SLL: Bundle Startlevel set to " + newSL); //$NON-NLS-1$ + } + } + } +} |