📄 bundleimpl.java
字号:
/* * Copyright (c) 2003-2004, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */package org.knopflerfish.framework;import java.io.*;import java.net.*;import java.security.*;import java.util.Set;import java.util.Dictionary;import java.util.List;import java.util.ArrayList;import java.util.Map;import java.util.HashSet;import java.util.HashMap;import java.util.Iterator;import org.osgi.framework.*;/** * Implementation of the Bundle object. * * @see org.osgi.framework.Bundle * @author Jan Stein */class BundleImpl implements Bundle { /** * Framework for bundle. */ final Framework framework; /** * Bundle identifier. */ final long id; /** * Bundle location identifier. */ final String location; /** * Bundle protect domain. */ final ProtectionDomain protectionDomain; /** * State of bundle. */ int state; /** * Packages that the bundle wants to export and import. */ BundlePackages bpkgs; /** * Bundle JAR data. */ BundleArchive archive; /** * Classloader for bundle. */ private BundleClassLoader classLoader = null; /** * Zombie classloaders for bundle. */ private Map /* String -> BundleClassLoader */ oldClassLoaders = null; /** * Directory for bundle data. */ protected FileTree bundleDir = null; /** * BundleContext for bundle. */ protected BundleContextImpl bundleContext = null; /** * BundleActivator for bundle. */ protected BundleActivator bactivator = null; /** * List of all nativeLibs that can be used in this bundle. * * pl: unused */ //protected List nativeLibs = null; /** * Set to true of bundle.start() has been called but * current start levels was too low to actually start the bundle. */ boolean bDelayedStart = false; /** * Construct a new Bundle empty. * * @param fw Framework for this bundle. */ BundleImpl(Framework fw, long id, String loc, ProtectionDomain pd) { this.framework = fw; this.id = id; this.location = loc; this.protectionDomain = pd; } /** * Construct a new Bundle based on a BundleArchive. * * @param bundlesDir Directory where to store the bundles all persistent data. * @param fw Framework for this bundle. * @param loc Location for new bundle. * @param in Bundle JAR as an inputstream. * @exception IOException If we fail to read and store our JAR bundle or if * the input data is corrupted. * @exception SecurityException If we don't have permission to import and export * bundle packages. */ BundleImpl(Framework fw, BundleArchive ba) { framework = fw; id = ba.getBundleId(); location = ba.getBundleLocation(); archive = ba; state = INSTALLED; doExportImport(); FileTree dataRoot = fw.getDataStorage(); if (dataRoot != null) { bundleDir = new FileTree(dataRoot, Long.toString(id)); } ProtectionDomain pd = null; if (fw.bPermissions) { try { URLStreamHandler handler = bpkgs.bundle.framework.bundleURLStreamhandler; URL bundleUrl = new URL(BundleURLStreamHandler.PROTOCOL, Long.toString(id), -1, "", handler); PermissionCollection pc = fw.permissions.getPermissionCollection(this); pd = new ProtectionDomain(new CodeSource(bundleUrl, (java.security.cert.Certificate[])null), pc); } catch (MalformedURLException e) { e.printStackTrace(); } } protectionDomain = pd; int oldStartLevel = archive.getStartLevel(); try { if(framework.startLevelService == null) { archive.setStartLevel(0); } else { if(oldStartLevel == -1) { archive.setStartLevel(framework.startLevelService.getInitialBundleStartLevel()); } else { } } } catch (Exception e) { Debug.println("Failed to set start level on #" + getBundleId() + ": " + e); } } // // Bundle interface // /** * Get bundle state. * * @see org.osgi.framework.Bundle#getState */ public int getState() { return state; } /** * Start this bundle. * * @see org.osgi.framework.Bundle#start */ synchronized public void start() throws BundleException { framework.checkAdminPermission(); int updState = getUpdatedState(); setPersistent(true); if(framework.startLevelService != null) { if(getStartLevel() > framework.startLevelService.getStartLevel()) { bDelayedStart = true; return; } } switch (updState) { case INSTALLED: throw new BundleException("Bundle.start: Failed, " + bpkgs.getResolveFailReason()); case RESOLVED: if (framework.active) { state = STARTING; bundleContext = new BundleContextImpl(this); try { AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws BundleException { final String ba = archive.getAttribute(Constants.BUNDLE_ACTIVATOR); boolean bStarted = false; ClassLoader oldLoader = null; if(Framework.SETCONTEXTCLASSLOADER) { oldLoader = Thread.currentThread().getContextClassLoader(); } try { // If SETCONTEXTCLASSLOADER, set the thread's context // class loader to the bundle class loader. This // is useful for debugging external libs using // the context class loader. if(Framework.SETCONTEXTCLASSLOADER) { Thread.currentThread().setContextClassLoader(getClassLoader()); } if (ba != null) { Class c = getClassLoader().loadClass(ba.trim()); bactivator = (BundleActivator)c.newInstance(); bactivator.start(bundleContext); bStarted = true; } else { // Check if we have a standard Main-class attribute as // in normal executable jar files. This is a slight // extension to the OSGi spec. final String mc = archive.getAttribute("Main-class"); if (mc != null) { if(Debug.packages) { Debug.println("starting main class " + mc); } Class mainClass = getClassLoader().loadClass(mc.trim()); bactivator = MainClassBundleActivator.create(getClassLoader(), mainClass); bactivator.start(bundleContext); bStarted = true; } } if(!bStarted) { // Even bundles without an activator is marked as // ACTIVE. // Should we possible log an information message to // make sure users are aware of the missing activator? } state = ACTIVE; startOnLaunch(true); } catch (Throwable t) { throw new BundleException("Bundle.start: BundleActivator start failed", t); } finally { if(Framework.SETCONTEXTCLASSLOADER) { Thread.currentThread().setContextClassLoader(oldLoader); } } return null; } }); } catch (PrivilegedActionException e) { removeBundleResources(); bundleContext.invalidate(); bundleContext = null; state = RESOLVED; throw (BundleException) e.getException(); } framework.listeners.bundleChanged(new BundleEvent(BundleEvent.STARTED, this)); break; } else { startOnLaunch(true); } case ACTIVE: return; case STARTING: // This happens if we call start from inside the BundleActivator.start method. // We don't allow it. throw new BundleException("Bundle.start called from BundleActivator.start"); case STOPPING: // This happens if we call start from inside the BundleActivator.stop method. // We don't allow it. throw new BundleException("Bundle.start called from BundleActivator.stop"); case UNINSTALLED: throw new IllegalStateException("Bundle.start: Bundle is in UNINSTALLED state"); } } /** * Check if setStartOnLaunch(false) is allowed. */ boolean allowSetStartOnLaunchFalse() { boolean bCompat = framework.startLevelService == null || framework.startLevelService.bCompat; return // never never touch on FW shutdown !framework.shuttingdown && !archive.isPersistent(); /* && // allow touch if in startlevel compatibility mode (bCompat || // ...also allow touch if not marked as persistant startlevel active !isPersistent()); */ } /** * Stop this bundle. * * @see org.osgi.framework.Bundle#stop */ synchronized public void stop() throws BundleException { framework.checkAdminPermission(); bDelayedStart = false; setPersistent(false); if(framework.startLevelService != null) { if(getStartLevel() <= framework.startLevelService.getStartLevel()) { if(state == ACTIVE) { bDelayedStart = true; } } } switch (state) { case INSTALLED: case RESOLVED: // We don't want this bundle to start on launch after it has been // stopped. (Don't apply during shutdown if (allowSetStartOnLaunchFalse()) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { startOnLaunch(false); return null; } }); } break; case ACTIVE: state = STOPPING; Throwable savedException = (Throwable) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Throwable res = null; if (allowSetStartOnLaunchFalse()) { startOnLaunch(false); } if (bactivator != null) { try { bactivator.stop(bundleContext); } catch (Throwable e) { res = e; } bactivator = null; } bundleContext.invalidate(); bundleContext = null; removeBundleResources(); state = RESOLVED; return res; } }); framework.listeners.bundleChanged(new BundleEvent(BundleEvent.STOPPED, this)); if (savedException != null) { throw new BundleException("Bundle.stop: BundleActivator stop failed", savedException); } break; case STARTING: // This happens if we call stop from inside the BundleActivator.start method. // We don't allow it. throw new BundleException("Bundle.start called from BundleActivator.stop"); case STOPPING: // This happens if we call stop from inside the BundleActivator.stop method. // We don't allow it. throw new BundleException("Bundle.stop called from BundleActivator.stop"); case UNINSTALLED: throw new IllegalStateException("Bundle.stop: Bundle is in UNINSTALLED state"); } } /** * Update this bundle. * * @see org.osgi.framework.Bundle#update */ public void update() throws BundleException { update(null); } /** * Update this bundle. * * @see org.osgi.framework.Bundle#update */ synchronized public void update(final InputStream in) throws BundleException { try { framework.checkAdminPermission(); final boolean wasActive = state == ACTIVE; switch (getUpdatedState()) { case ACTIVE: stop(); // Fall through case INSTALLED: case RESOLVED: // Load new bundle try { final BundleImpl thisBundle = this; final int oldStartLevel = getStartLevel(); AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws BundleException { BundleArchive newArchive = null; HeaderDictionary newHeaders; try { // New bundle as stream supplied? InputStream bin; if (in == null) { // Try Bundle-UpdateLocation String update = archive.getAttribute(Constants.BUNDLE_UPDATELOCATION); if (update == null) { // Take original location update = location; } bin = (new URL(update)).openStream(); } else { bin = in; } newArchive = framework.storage.replaceBundleJar(archive, bin); newArchive.setStartLevel(oldStartLevel); } catch (Exception e) { if (newArchive != null) { newArchive.purge(); } if (wasActive) { try { start(); } catch (BundleException be) { framework.listeners.frameworkError(thisBundle, be); } } throw new BundleException("Failed to get update bundle", e); } // Remove this bundles packages boolean allRemoved = bpkgs.unregisterPackages(false); // Loose old bundle if no exporting packages left if (classLoader != null) { if (allRemoved) { classLoader.purge(); } else { saveZombiePackages(); } classLoader = null; } // Activate new bundle state = INSTALLED; BundleArchive oldArchive = archive; archive = newArchive; doExportImport(); // Purge old archive if (allRemoved) { oldArchive.purge(); } checkEE(newArchive); // Broadcast updated event framework.listeners.bundleChanged(new BundleEvent(BundleEvent.UPDATED, thisBundle)); // Restart bundles previously stopped in the operation if (wasActive) { try { thisBundle.start(); } catch (BundleException be) { framework.listeners.frameworkError(thisBundle, be); } } return null; } }); } catch (PrivilegedActionException e) { throw (BundleException) e.getException(); } break; case STARTING: // Wait for RUNNING state, this doesn't happen now // since we are synchronized. throw new IllegalStateException("Bundle.update: Bundle is in STARTING state"); case STOPPING: // Wait for RESOLVED state, this doesn't happen now // since we are synchronized. throw new IllegalStateException("Bundle.update: Bundle is in STOPPING state"); case UNINSTALLED: throw new IllegalStateException("Bundle.update: Bundle is in UNINSTALLED state"); } } finally { if (in != null) { try { in.close(); } catch (IOException ignore) {}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -