| /******************************************************************************* |
| * 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$ |
| } |
| } |
| } |
| } |