You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2008/09/01 17:08:10 UTC
svn commit: r690991 [5/20] - in /cxf/sandbox/dosgi: ./ discovery/
discovery/local/ discovery/local/src/ discovery/local/src/main/
discovery/local/src/main/java/ discovery/local/src/main/java/org/
discovery/local/src/main/java/org/apache/ discovery/loca...
Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=690991&view=auto
==============================================================================
--- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/Felix.java (added)
+++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/Felix.java Mon Sep 1 08:08:01 2008
@@ -0,0 +1,4506 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.security.Permission;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import org.apache.felix.framework.cache.BundleArchive;
+import org.apache.felix.framework.cache.BundleCache;
+import org.apache.felix.framework.ext.SecurityProvider;
+import org.apache.felix.framework.searchpolicy.ContentClassLoader;
+import org.apache.felix.framework.searchpolicy.ContentLoaderImpl;
+import org.apache.felix.framework.searchpolicy.ModuleDefinition;
+import org.apache.felix.framework.searchpolicy.R4SearchPolicy;
+import org.apache.felix.framework.searchpolicy.R4SearchPolicyCore;
+import org.apache.felix.framework.searchpolicy.ResolveException;
+import org.apache.felix.framework.searchpolicy.ResolveListener;
+import org.apache.felix.framework.searchpolicy.URLPolicyImpl;
+import org.apache.felix.framework.util.EventDispatcher;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.MapToDictionary;
+import org.apache.felix.framework.util.SecureAction;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.felix.framework.util.Util;
+import org.apache.felix.framework.util.manifestparser.Capability;
+import org.apache.felix.framework.util.manifestparser.ManifestParser;
+import org.apache.felix.framework.util.manifestparser.R4Attribute;
+import org.apache.felix.framework.util.manifestparser.R4Library;
+import org.apache.felix.framework.util.manifestparser.R4LibraryClause;
+import org.apache.felix.framework.util.manifestparser.Requirement;
+import org.apache.felix.moduleloader.ICapability;
+import org.apache.felix.moduleloader.IContentLoader;
+import org.apache.felix.moduleloader.IModule;
+import org.apache.felix.moduleloader.IModuleDefinition;
+import org.apache.felix.moduleloader.IModuleFactory;
+import org.apache.felix.moduleloader.IRequirement;
+import org.apache.felix.moduleloader.IWire;
+import org.apache.felix.moduleloader.ModuleEvent;
+import org.apache.felix.moduleloader.ModuleFactoryImpl;
+import org.apache.felix.moduleloader.ModuleImpl;
+import org.osgi.framework.AdminPermission;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.PackagePermission;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServicePermission;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.startlevel.StartLevel;
+
+public class Felix extends FelixBundle
+{
+ // The secure action used to do privileged calls
+ static SecureAction m_secureAction = new SecureAction();
+
+ // The extension manager to handle extension bundles
+ ExtensionManager m_extensionManager;
+
+ // Logging related member variables.
+ private Logger m_logger = null; // TODO: KARL - Why package private?
+ // Immutable config properties.
+ private Map m_configMap = null;
+ // Mutable configuration properties passed into constructor.
+ private Map m_configMutableMap = null;
+
+ // MODULE FACTORY.
+ private IModuleFactory m_factory = null;
+ private R4SearchPolicyCore m_policyCore = null;
+
+ // Object used as a lock when calculating which bundles
+ // when performing an operation on one or more bundles.
+ private Object[] m_bundleLock = new Object[0];
+
+ // Maps a bundle location to a bundle location;
+ // used to reserve a location when installing a bundle.
+ private Map m_installRequestMap = new HashMap();
+ // This lock must be acquired to modify m_installRequestMap;
+ // to help avoid deadlock this lock as priority 1 and should
+ // be acquired before locks with lower priority.
+ private Object[] m_installRequestLock_Priority1 = new Object[0];
+
+ // Maps a bundle location to a bundle.
+ private HashMap m_installedBundleMap = new HashMap();
+ private SortedMap m_installedBundleIndex = new TreeMap();
+ // This lock must be acquired to modify m_installedBundleMap;
+ // to help avoid deadlock this lock as priority 2 and should
+ // be acquired before locks with lower priority.
+ private Object[] m_installedBundleLock_Priority2 = new Object[0];
+
+ // An array of uninstalled bundles before a refresh occurs.
+ private FelixBundle[] m_uninstalledBundles = null;
+ // This lock must be acquired to modify m_uninstalledBundles;
+ // to help avoid deadlock this lock as priority 3 and should
+ // be acquired before locks with lower priority.
+ private Object[] m_uninstalledBundlesLock_Priority3 = new Object[0];
+
+ // Framework's active start level.
+ private int m_activeStartLevel =
+ FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
+
+ // Local file system cache.
+ private BundleCache m_cache = null;
+
+ // System bundle bundle info instance.
+ private BundleInfo m_systemBundleInfo = null;
+ // System bundle activator list.
+ List m_activatorList = null;
+
+ // Next available bundle identifier.
+ private long m_nextId = 1L;
+ private Object m_nextIdLock = new Object[0];
+
+ // List of event listeners.
+ private EventDispatcher m_dispatcher = null;
+
+ // Service registry.
+ private ServiceRegistry m_registry = null;
+
+ // Reusable bundle URL stream handler.
+ private URLStreamHandler m_bundleStreamHandler = null;
+
+ // Execution environment.
+ private String m_executionEnvironment = "";
+ private Set m_executionEnvironmentCache = new HashSet();
+
+ // Shutdown thread.
+ private Thread m_shutdownThread = null;
+
+ /**
+ * Creates a new Felix framework instance with a default logger.
+ *
+ * @param configMutableMap An map for obtaining configuration properties,
+ * may be <tt>null</tt>.
+ * @param activatorList A list of System Bundle activators.
+ *
+ * @see #Felix(Logger, Map, List)
+ */
+ public Felix(Map configMutableMap, List activatorList)
+ {
+ this(null, configMutableMap, activatorList);
+ }
+
+ /**
+ * <p>
+ * This method creates the framework instance; instances of the framework
+ * are not active until they are started. The constructor accepts a
+ * <tt>Map</tt> instance that will be used to obtain configuration or
+ * framework properties. Configuration properties are used internally by
+ * the framework and its extensions to alter its default behavior.
+ * Framework properties are used by bundles and are accessible from
+ * <tt>BundleContext.getProperty()</tt>. This map instance is used
+ * directly (i.e., it is not copied), which means that it is possible to
+ * change the property values externally at run time, but this is strongly
+ * discouraged for the framework's configuration properties.
+ * </p>
+ * <p>
+ * Configuration properties are the sole means to configure the framework's
+ * default behavior; the framework does not refer to any system properties for
+ * configuration information. If a <tt>Map</tt> is supplied to this method
+ * for configuration properties, then the framework will consult the
+ * <tt>Map</tt> instance for any and all configuration properties. It is
+ * possible to specify a <tt>null</tt> for the configuration property map,
+ * in which case the framework will use its default behavior in all cases.
+ * However, if the
+ * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
+ * is used, then at a minimum a profile name or profile directory must
+ * be specified.
+ * </p>
+ * <p>
+ * The following configuration properties can be specified:
+ * </p>
+ * <ul>
+ * <li><tt>felix.log.level</tt> - An integer value indicating the degree
+ * of logging reported by the framework; the higher the value the more
+ * logging is reported. If zero ('0') is specified, then logging is
+ * turned off completely. The log levels match those specified in the
+ * OSGi Log Service (i.e., 1 = error, 2 = warning, 3 = information,
+ * and 4 = debug). The default value is 1.
+ * </li>
+ * <li><tt>felix.startlevel.framework</tt> - The initial start level
+ * of the framework once it starts execution; the default
+ * value is 1.
+ * </li>
+ * <li><tt>felix.startlevel.bundle</tt> - The default start level for
+ * newly installed bundles; the default value is 1.
+ * </li>
+ * <li><tt>framework.service.urlhandlers</tt> - Flag to indicate whether
+ * to activate the URL Handlers service for the framework instance;
+ * the default value is "<tt>true</tt>". Activating the URL Handlers
+ * service will result in the <tt>URL.setURLStreamHandlerFactory()</tt>
+ * and <tt>URLConnection.setContentHandlerFactory()</tt> being called.
+ * </li>
+ * <li><tt>felix.embedded.execution</tt> - Flag to indicate whether
+ * the framework is embedded into a host application; the default value is
+ * "<tt>false</tt>". If this flag is "<tt>true</tt>" then the framework
+ * will not called <tt>System.exit()</tt> upon termination.
+ * </li>
+ * <li><tt>felix.strict.osgi</tt> - Flag to indicate whether the framework is
+ * running in strict OSGi mode; the default value is "<tt>true</tt>".
+ * If this flag is "<tt>false</tt>" it enables a non-OSGi-compliant
+ * feature by persisting <tt>BundleActivator</tt>s that implement
+ * <tt>Serializable</tt>. This feature is not recommended since
+ * it is non-compliant.
+ * </li>
+ * </ul>
+ * <p>
+ * Besides the above framework configuration properties, it is also
+ * possible to specify properties for the bundle cache. The available
+ * bundle cache properties depend on the cache implementation
+ * being used. For the properties of the default bundle cache, refer to the
+ * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
+ * API documentation.
+ * </p>
+ * <p>
+ * The <a href="Main.html"><tt>Main</tt></a> class implements some
+ * functionality for default property file handling, which makes it
+ * possible to specify configuration properties and framework properties
+ * in files that are automatically loaded when starting the framework. If you
+ * plan to create your own framework instance, you may be
+ * able to take advantage of the features it provides; refer to its
+ * class documentation for more information.
+ * </p>
+ *
+ * @param logger The logger for use by the framework or <code>null</code>
+ * use the default logger.
+ * @param configMutableMap A map for obtaining configuration properties,
+ * may be <tt>null</tt>.
+ * @param activatorList A list of System Bundle activators.
+ **/
+ public Felix(Logger logger, Map configMutableMap, List activatorList)
+ {
+ // Initialize member variables.
+ m_configMutableMap = (configMutableMap == null)
+ ? new StringMap(false) : configMutableMap;
+ m_configMap = createUnmodifiableMap(m_configMutableMap);
+ m_activatorList = (activatorList == null) ? new ArrayList() : activatorList;
+
+ // Create logger with appropriate log level. Even though the
+ // logger needs the system bundle's context for tracking log
+ // services, it is created now because it is needed before
+ // the system bundle is created. The system bundle's context
+ // will be set below after the system bundle is created.\
+ m_logger = (logger == null) ? new Logger() : logger;
+ try
+ {
+ m_logger.setLogLevel(
+ Integer.parseInt(
+ (String) m_configMutableMap.get(FelixConstants.LOG_LEVEL_PROP)));
+ }
+ catch (NumberFormatException ex)
+ {
+ // Ignore and just use the default logging level.
+ }
+
+ // Initialize framework properties.
+ initializeFrameworkProperties();
+
+ // Create the bundle cache since we need it for the system bundle
+ // archive, which in turn is needed by the system bundle info,
+ // which we need to keep track of the framework state.
+ try
+ {
+ m_cache = new BundleCache(m_logger, m_configMap);
+ }
+ catch (Exception ex)
+ {
+ System.err.println("Error creating bundle cache:");
+ ex.printStackTrace();
+
+ // Only shutdown the JVM if the framework is running stand-alone.
+ String embedded = (String) m_configMap.get(
+ FelixConstants.EMBEDDED_EXECUTION_PROP);
+ boolean isEmbedded = (embedded == null)
+ ? false : embedded.equals("true");
+ if (!isEmbedded)
+ {
+ m_secureAction.exit(-1);
+ }
+ else
+ {
+ throw new RuntimeException(ex.toString());
+ }
+ }
+
+ // Create the module factory and add the system bundle
+ // module to it, since we need the system bundle info
+ // object to keep track of the framework state.
+ m_factory = new ModuleFactoryImpl(m_logger);
+ m_systemBundleInfo = new BundleInfo(
+ m_logger, new SystemBundleArchive(m_cache), null);
+ m_extensionManager =
+ new ExtensionManager(m_logger, m_configMap, m_systemBundleInfo);
+ m_systemBundleInfo.addModule(
+ m_factory.createModule("0", m_extensionManager));
+ }
+
+ private Map createUnmodifiableMap(Map mutableMap)
+ {
+ Map result = Collections.unmodifiableMap(mutableMap);
+
+ // Work around a bug in certain version of J9 where a call to
+ // Collections.unmodifiableMap().keySet().iterator() throws
+ // a NoClassDefFoundError. We try to detect this and return
+ // the given mutableMap instead.
+ try
+ {
+ result.keySet().iterator();
+ }
+ catch (NoClassDefFoundError ex)
+ {
+ return mutableMap;
+ }
+
+ return result;
+ }
+
+ //
+ // System Bundle methods.
+ //
+
+ /* package private */ BundleInfo getInfo()
+ {
+ return m_systemBundleInfo;
+ }
+
+ public BundleContext getBundleContext()
+ {
+// TODO: SECURITY - We need a security check here.
+ if (m_systemBundleInfo != null)
+ {
+ return m_systemBundleInfo.getBundleContext();
+ }
+ return null;
+ }
+
+ public long getBundleId()
+ {
+ return 0;
+ }
+
+ public URL getEntry(String name)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.RESOURCE));
+ }
+ catch (Exception e)
+ {
+ return null; // No permission
+ }
+ }
+
+ return getBundleEntry(this, name);
+ }
+
+ public Enumeration getEntryPaths(String path)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.RESOURCE));
+ }
+ catch (Exception e)
+ {
+ return null; // No permission
+ }
+ }
+
+ return getBundleEntryPaths(this, path);
+ }
+
+ public Enumeration findEntries(String path, String filePattern, boolean recurse)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.RESOURCE));
+ }
+ catch (Exception e)
+ {
+ return null; // No permission
+ }
+ }
+
+ return findBundleEntries(this, path, filePattern, recurse);
+ }
+
+ public Dictionary getHeaders()
+ {
+ return getHeaders(Locale.getDefault().toString());
+ }
+
+ public Dictionary getHeaders(String locale)
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.METADATA));
+ }
+ return getBundleHeaders(this, locale);
+ }
+
+ public long getLastModified()
+ {
+ if (m_systemBundleInfo != null)
+ {
+ return m_systemBundleInfo.getLastModified();
+ }
+ return -1;
+ }
+
+ public String getLocation()
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.METADATA));
+ }
+ return Constants.SYSTEM_BUNDLE_LOCATION;
+ }
+
+ public URL getResource(String name)
+ {
+ return getBundleResource(this, name);
+ }
+
+ public Enumeration getResources(String name) throws IOException
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.RESOURCE));
+ }
+ catch (Exception e)
+ {
+ return null; // No permission
+ }
+ }
+
+ return getBundleResources(this, name);
+ }
+
+ public ServiceReference[] getRegisteredServices()
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ServiceReference[] refs = getBundleRegisteredServices(this);
+
+ if (refs == null)
+ {
+ return refs;
+ }
+
+ List result = new ArrayList();
+
+ for (int i = 0;i < refs.length;i++)
+ {
+ String[] objectClass = (String[]) refs[i].getProperty(
+ Constants.OBJECTCLASS);
+
+ if (objectClass == null)
+ {
+ continue;
+ }
+
+ for (int j = 0;j < objectClass.length;j++)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new ServicePermission(
+ objectClass[j], ServicePermission.GET));
+
+ result.add(refs[i]);
+
+ break;
+ }
+ catch (Exception ex)
+ {
+ // Silently ignore.
+ }
+ }
+ }
+
+ if (result.isEmpty())
+ {
+ return null;
+ }
+
+ return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
+ }
+ else
+ {
+ return getBundleRegisteredServices(this);
+ }
+ }
+
+ public ServiceReference[] getServicesInUse()
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ServiceReference[] refs = getBundleServicesInUse(this);
+
+ if (refs == null)
+ {
+ return refs;
+ }
+
+ List result = new ArrayList();
+
+ for (int i = 0;i < refs.length;i++)
+ {
+ String[] objectClass = (String[]) refs[i].getProperty(
+ Constants.OBJECTCLASS);
+
+ if (objectClass == null)
+ {
+ continue;
+ }
+
+ for (int j = 0;j < objectClass.length;j++)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new ServicePermission(
+ objectClass[j], ServicePermission.GET));
+
+ result.add(refs[i]);
+
+ break;
+ }
+ catch (Exception e)
+ {
+ // Silently ignore.
+ }
+ }
+ }
+
+ if (result.isEmpty())
+ {
+ return null;
+ }
+
+ return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
+ }
+
+ return getBundleServicesInUse(this);
+ }
+
+ public int getState()
+ {
+ return m_systemBundleInfo.getState();
+ }
+
+ public String getSymbolicName()
+ {
+ return Constants.SYSTEM_BUNDLE_LOCATION;
+ }
+
+ public boolean hasPermission(Object obj)
+ {
+ return true;
+ }
+
+ Object getSignerMatcher()
+ {
+ return null;
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ try
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.CLASS));
+ }
+ catch (Exception e)
+ {
+ throw new ClassNotFoundException("No permission.", e);
+ }
+ }
+
+ return loadBundleClass(this, name);
+ }
+
+ public synchronized void start() throws BundleException
+ {
+ // The system bundle is only started once and it
+ // is started by the framework.
+ if (getState() == Bundle.ACTIVE)
+ {
+ return;
+ }
+ else if (m_systemBundleInfo.getState() != Bundle.INSTALLED)
+ {
+ throw new IllegalStateException("Invalid framework state: " + m_systemBundleInfo.getState());
+ }
+
+ // The framework is now in its startup sequence.
+ m_systemBundleInfo.setState(Bundle.STARTING);
+
+ // Create default bundle stream handler.
+ m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
+
+ // Create service registry.
+ m_registry = new ServiceRegistry(m_logger);
+ // Add a listener to the service registry; this is
+ // used to distribute service registry events to
+ // service listeners.
+ m_registry.addServiceListener(new ServiceListener() {
+ public void serviceChanged(ServiceEvent event)
+ {
+ fireServiceEvent(event);
+ }
+ });
+
+ // Create search policy for module loader.
+ m_policyCore = new R4SearchPolicyCore(m_logger, m_configMap);
+
+ // Add a resolver listener to the search policy
+ // so that we will be notified when modules are resolved
+ // in order to update the bundle state.
+ m_policyCore.addResolverListener(new ResolveListener() {
+ public void moduleResolved(ModuleEvent event)
+ {
+ FelixBundle bundle = null;
+ try
+ {
+ long id = Util.getBundleIdFromModuleId(
+ event.getModule().getId());
+ if (id > 0)
+ {
+ // Update the bundle's state to resolved when the
+ // current module is resolved; just ignore resolve
+ // events for older revisions since this only occurs
+ // when an update is done on an unresolved bundle
+ // and there was no refresh performed.
+ bundle = (FelixBundle) getBundle(id);
+
+ // Lock the bundle first.
+ try
+ {
+ acquireBundleLock(bundle);
+ if (bundle.getInfo().getCurrentModule() == event.getModule())
+ {
+ if (bundle.getInfo().getState() != Bundle.INSTALLED)
+ {
+ m_logger.log(
+ Logger.LOG_WARNING,
+ "Received a resolve event for a bundle that has already been resolved.");
+ }
+ else
+ {
+ bundle.getInfo().setState(Bundle.RESOLVED);
+ fireBundleEvent(BundleEvent.RESOLVED, bundle);
+ }
+ }
+ }
+ finally
+ {
+ releaseBundleLock(bundle);
+ }
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ // Ignore.
+ }
+ }
+
+ public void moduleUnresolved(ModuleEvent event)
+ {
+ // We can ignore this, because the only time it
+ // should happen is when a refresh occurs. The
+ // refresh operation resets the bundle's state
+ // by calling BundleInfo.reset(), thus it is not
+ // necessary for us to reset the bundle's state
+ // here.
+ }
+ });
+
+ m_policyCore.setModuleFactory(m_factory);
+
+ // Initialize event dispatcher.
+ m_dispatcher = EventDispatcher.start(m_logger);
+
+ // Reload the cached bundles bundles before creating and starting
+ // the system bundle, since we want all cached bundles to be reloaded
+ // when we activate the system bundle and any subsequent custom
+ // framework activators passed into the framework constructor.
+ BundleArchive[] archives = null;
+
+ // First get cached bundle identifiers.
+ try
+ {
+ archives = m_cache.getArchives();
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to list saved bundles.",
+ ex);
+ archives = null;
+ }
+
+ // create the system bundle that is responsible for providing specific
+ // container related services.
+ IContentLoader cl = m_extensionManager;
+ cl.setSearchPolicy(
+ new R4SearchPolicy(
+ m_policyCore, m_systemBundleInfo.getCurrentModule()));
+ m_factory.setContentLoader(
+ m_systemBundleInfo.getCurrentModule(),
+ cl);
+
+ try
+ {
+ addSecurity(this);
+ }
+ catch (Exception e)
+ {
+ // This should not happen
+ }
+
+ // Note: we need this ordering to launch:
+ // 1) create all stuff of the system bundle (extension manager needs it)
+ // 2) install all bundles from cache (will start extension bundles)
+ // 3) start the system bundle (will start custom activators)
+ // 4) start the other bundles via the start level
+ // it is important to keep this order because bundles are installed
+ // from added activators in step 3 and extension bundles are started
+ // in 2 and need the stuff from 1.
+ m_installedBundleMap.put(
+ m_systemBundleInfo.getLocation(), this);
+ m_installedBundleIndex.put(new Long(0), this);
+
+ // Create system bundle activator.
+ m_systemBundleInfo.setActivator(new SystemBundleActivator());
+
+ // Create the bundle context for the system bundle and
+ // then activate it.
+ m_systemBundleInfo.setBundleContext(
+ new BundleContextImpl(m_logger, this, this));
+
+ FelixBundle bundle = null;
+
+ // Now install all cached bundles.
+ for (int i = 0; (archives != null) && (i < archives.length); i++)
+ {
+ try
+ {
+ // Keep track of the max bundle ID currently in use since we
+ // will need to use this as our next bundle ID value if the
+ // persisted value cannot be read.
+ m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
+
+ // It is possible that a bundle in the cache was previously
+ // uninstalled, but not completely deleted (perhaps because
+ // of a crash or a locked file), so if we see an archive
+ // with an UNINSTALLED persistent state, then try to remove
+ // it now.
+ if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
+ {
+ m_cache.remove(archives[i]);
+ }
+ // Otherwise re-install the cached bundle.
+ else
+ {
+ // Install the cached bundle.
+ bundle = (FelixBundle) installBundle(
+ archives[i].getId(), archives[i].getLocation(), null);
+ }
+ }
+ catch (Exception ex)
+ {
+ex.printStackTrace();
+ fireFrameworkEvent(FrameworkEvent.ERROR, this, ex);
+ try
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to re-install " + archives[i].getLocation(),
+ ex);
+ }
+ catch (Exception ex2)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to re-install cached bundle.",
+ ex);
+ }
+ // TODO: FRAMEWORK - Perhaps we should remove the cached bundle?
+ }
+ }
+
+ // Now that we have loaded all cached bundles and have determined the
+ // max bundle ID of cached bundles, we need to try to load the next
+ // bundle ID from persistent storage. In case of failure, we should
+ // keep the max value.
+ m_nextId = Math.max(m_nextId, loadNextId());
+
+ // Get the framework's default start level.
+ int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
+ String s = (String) m_configMap.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP);
+ if (s != null)
+ {
+ try
+ {
+ startLevel = Integer.parseInt(s);
+ }
+ catch (NumberFormatException ex)
+ {
+ startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
+ }
+ }
+
+ // Now that the cached bundles are reloaded,
+ // activating all custom framework activators.
+ try
+ {
+ // Manually resolve the System Bundle, which will cause its
+ // state to be set to RESOLVED.
+ try
+ {
+ m_policyCore.resolve(m_systemBundleInfo.getCurrentModule());
+ }
+ catch (ResolveException ex)
+ {
+ // This should never happen.
+ throw new BundleException(
+ "Unresolved package in System Bundle:"
+ + ex.getRequirement());
+ }
+
+ Felix.m_secureAction.startActivator(m_systemBundleInfo.getActivator(),
+ m_systemBundleInfo.getBundleContext());
+ }
+ catch (Throwable ex)
+ {
+ m_factory = null;
+ EventDispatcher.shutdown();
+ m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
+ throw new RuntimeException("Unable to start system bundle.");
+ }
+
+ // Now that the system bundle is successfully created we can give
+ // its bundle context to the logger so that it can track log services.
+ m_logger.setSystemBundleContext(m_systemBundleInfo.getBundleContext());
+
+ // Set the start level using the start level service;
+ // this ensures that all start level requests are
+ // serialized.
+ try
+ {
+ StartLevel sl = (StartLevel) getService(
+ getBundle(0),getServiceReferences((FelixBundle) getBundle(0),
+ StartLevel.class.getName(), null, true)[0]);
+ if (sl instanceof StartLevelImpl)
+ {
+ ((StartLevelImpl) sl).setStartLevelAndWait(startLevel);
+ }
+ else
+ {
+ sl.setStartLevel(startLevel);
+ }
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // Should never happen.
+ }
+
+ // The framework is now running.
+ m_systemBundleInfo.setState(Bundle.ACTIVE);
+
+ // Fire started event for system bundle.
+ fireBundleEvent(BundleEvent.STARTED, this);
+
+ // Send a framework event to indicate the framework has started.
+ fireFrameworkEvent(FrameworkEvent.STARTED, this, null);
+ }
+
+ /**
+ * This method cleanly shuts down the framework, it must be called at the
+ * end of a session in order to shutdown all active bundles.
+ **/
+ public void stop() throws BundleException
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.EXECUTE));
+ }
+
+ stopBundle(this, true);
+ }
+
+ public void stopAndWait()
+ {
+ // Shut the framework down by calling stop() on the system bundle.
+ // Since stop() on the system bundle will return immediately, we
+ // will synchronize on the framework instance so we can use it to
+ // be notified when the shutdown is complete.
+ synchronized (this)
+ {
+ if (m_systemBundleInfo.getState() == Bundle.ACTIVE)
+ {
+ try
+ {
+ getBundle(0).stop();
+ }
+ catch (BundleException ex)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, this, ex);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error stopping system bundle.",
+ ex);
+ }
+ }
+
+ while (m_systemBundleInfo.getState() != Bundle.UNINSTALLED)
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException ex)
+ {
+ // Keep waiting if necessary.
+ }
+ }
+ }
+ }
+
+ public void uninstall() throws BundleException
+ {
+ throw new BundleException("Cannot uninstall the system bundle.");
+ }
+
+ public void update() throws BundleException
+ {
+ update(null);
+ }
+
+ public void update(InputStream is) throws BundleException
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(new AdminPermission(this,
+ AdminPermission.EXECUTE));
+ }
+
+ // TODO: FRAMEWORK - This is supposed to stop and then restart the framework.
+ throw new BundleException("System bundle update not implemented yet.");
+ }
+
+ public String toString()
+ {
+ return getSymbolicName() + " [" + getBundleId() +"]";
+ }
+
+ /**
+ * Returns the active start level of the framework; this method
+ * implements functionality for the Start Level service.
+ * @return The active start level of the framework.
+ **/
+ protected int getStartLevel()
+ {
+ return m_activeStartLevel;
+ }
+
+ /**
+ * Implements the functionality of the <tt>setStartLevel()</tt>
+ * method for the StartLevel service, but does not do the security or
+ * parameter check. The security and parameter check are done in the
+ * StartLevel service implementation because this method is called on
+ * a separate thread and the caller's thread would already be gone if
+ * we did the checks in this method. This method should not be called
+ * directly.
+ * @param requestedLevel The new start level of the framework.
+ **/
+ protected void setFrameworkStartLevel(int requestedLevel)
+ {
+ Bundle[] bundles = null;
+
+ // Synchronization for changing the start level is rather loose.
+ // The install lock is grabbed initially to atomically change the
+ // framework's start level and to grab a sorted snapshot of the
+ // currently installed bundles, but then this lock is freed immediately.
+ // No locks are held while processing the currently installed bundles
+ // for starting/stopping based on the new start level. The only locking
+ // that occurs is for individual bundles when startBundle()/stopBundle()
+ // is called, but this locking is done in the respective method.
+ //
+ // This approach does mean that it is possible for a for individual
+ // bundle states to change during this operation. For example, bundle
+ // start levels can be changed or bundles can be uninstalled. If a
+ // bundle's start level changes, then it is possible for it to be
+ // processed out of order. Uninstalled bundles are just logged and
+ // ignored. I had a bit of discussion with Peter Kriens about these
+ // issues and he felt they were consistent with the spec, which
+ // intended Start Level to have some leeway.
+ //
+ // Calls to this method are only made by the start level thread, which
+ // serializes framework start level changes. Thus, it is not possible
+ // for two requests to change the framework's start level to interfere
+ // with each other.
+
+ synchronized (m_installedBundleLock_Priority2)
+ {
+ // Determine if we are lowering or raising the
+ // active start level.
+ boolean lowering = (requestedLevel < m_activeStartLevel);
+
+ // Record new start level.
+ m_activeStartLevel = requestedLevel;
+
+ // Get a snapshot of all installed bundles.
+ bundles = getBundles();
+
+ // Sort bundle array by start level either ascending or
+ // descending depending on whether the start level is being
+ // lowered or raised to that the bundles can be efficiently
+ // processed in order. Within a start level sort by bundle ID.
+ Comparator comparator = null;
+ if (lowering)
+ {
+ // Sort descending to stop highest start level first.
+ comparator = new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ FelixBundle b1 = (FelixBundle) o1;
+ FelixBundle b2 = (FelixBundle) o2;
+ if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return 1;
+ }
+ else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return -1;
+ }
+ else if (b1.getBundleId() < b2.getBundleId())
+ {
+ return 1;
+ }
+ return -1;
+ }
+ };
+ }
+ else
+ {
+ // Sort ascending to start lowest start level first.
+ comparator = new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ FelixBundle b1 = (FelixBundle) o1;
+ FelixBundle b2 = (FelixBundle) o2;
+ if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return 1;
+ }
+ else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
+ < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
+ {
+ return -1;
+ }
+ else if (b1.getBundleId() > b2.getBundleId())
+ {
+ return 1;
+ }
+ return -1;
+ }
+ };
+ }
+
+ Arrays.sort(bundles, comparator);
+ }
+
+ // Stop or start the bundles according to the start level.
+ for (int i = 0; (bundles != null) && (i < bundles.length); i++)
+ {
+ FelixBundle impl = (FelixBundle) bundles[i];
+
+ // Ignore the system bundle, since its start() and
+ // stop() methods get called explicitly in Felix.start()
+ // and Felix.shutdown(), respectively.
+ if (impl.getInfo().getBundleId() == 0)
+ {
+ continue;
+ }
+
+ // Lock the current bundle.
+ acquireBundleLock(impl);
+
+ try
+ {
+ // Start the bundle if necessary.
+ if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
+ (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
+ <= m_activeStartLevel))
+ {
+ try
+ {
+ startBundle(impl, false);
+ }
+ catch (Throwable th)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error starting " + impl.getInfo().getLocation(), th);
+ }
+ }
+ // Stop the bundle if necessary.
+ else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > m_activeStartLevel)
+ {
+ try
+ {
+ stopBundle(impl, false);
+ }
+ catch (Throwable th)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Error stopping " + impl.getInfo().getLocation(), th);
+ }
+ }
+ }
+ finally
+ {
+ // Always release bundle lock.
+ releaseBundleLock(impl);
+ }
+ // Hint to GC to collect bundle; not sure why this
+ // is necessary, but it appears to help.
+ bundles[i] = null;
+ }
+
+ if (m_systemBundleInfo.getState() == Bundle.ACTIVE)
+ {
+ fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, this, null);
+ }
+ }
+
+ /**
+ * Returns the start level into which newly installed bundles will
+ * be placed by default; this method implements functionality for
+ * the Start Level service.
+ * @return The default start level for newly installed bundles.
+ **/
+ protected int getInitialBundleStartLevel()
+ {
+ String s = (String) m_configMap.get(FelixConstants.BUNDLE_STARTLEVEL_PROP);
+
+ if (s != null)
+ {
+ try
+ {
+ int i = Integer.parseInt(s);
+ return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
+ }
+ catch (NumberFormatException ex)
+ {
+ // Ignore and return the default value.
+ }
+ }
+ return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
+ }
+
+ /**
+ * Sets the default start level into which newly installed bundles
+ * will be placed; this method implements functionality for the Start
+ * Level service.
+ * @param startLevel The new default start level for newly installed
+ * bundles.
+ * @throws java.lang.IllegalArgumentException If the specified start
+ * level is not greater than zero.
+ * @throws java.security.SecurityException If the caller does not
+ * have <tt>AdminPermission</tt>.
+ **/
+ protected void setInitialBundleStartLevel(int startLevel)
+ {
+ if (startLevel <= 0)
+ {
+ throw new IllegalArgumentException(
+ "Initial start level must be greater than zero.");
+ }
+
+ m_configMutableMap.put(
+ FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel));
+ }
+
+ /**
+ * Returns the start level for the specified bundle; this method
+ * implements functionality for the Start Level service.
+ * @param bundle The bundle to examine.
+ * @return The start level of the specified bundle.
+ * @throws java.lang.IllegalArgumentException If the specified
+ * bundle has been uninstalled.
+ **/
+ protected int getBundleStartLevel(Bundle bundle)
+ {
+ if (bundle.getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalArgumentException("Bundle is uninstalled.");
+ }
+
+ return ((FelixBundle) bundle).getInfo().getStartLevel(getInitialBundleStartLevel());
+ }
+
+ /**
+ * Sets the start level of the specified bundle; this method
+ * implements functionality for the Start Level service.
+ * @param bundle The bundle whose start level is to be modified.
+ * @param startLevel The new start level of the specified bundle.
+ * @throws java.lang.IllegalArgumentException If the specified
+ * bundle is the system bundle or if the bundle has been
+ * uninstalled.
+ * @throws java.security.SecurityException If the caller does not
+ * have <tt>AdminPermission</tt>.
+ **/
+ protected void setBundleStartLevel(Bundle bundle, int startLevel)
+ {
+ // Acquire bundle lock.
+ acquireBundleLock((FelixBundle) bundle);
+
+ Throwable rethrow = null;
+
+ try
+ {
+ if (bundle.getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalArgumentException("Bundle is uninstalled.");
+ }
+
+ if (startLevel >= 1)
+ {
+ FelixBundle impl = (FelixBundle) bundle;
+ impl.getInfo().setStartLevel(startLevel);
+
+ try
+ {
+ // Start the bundle if necessary.
+ if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
+ (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
+ <= m_activeStartLevel))
+ {
+ startBundle(impl, false);
+ }
+ // Stop the bundle if necessary.
+ else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
+ > m_activeStartLevel)
+ {
+ stopBundle(impl, false);
+ }
+ }
+ catch (Throwable th)
+ {
+ rethrow = th;
+ m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
+ }
+ }
+ else
+ {
+ m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
+ }
+ }
+ finally
+ {
+ // Always release bundle lock.
+ releaseBundleLock((FelixBundle) bundle);
+ }
+
+ if (rethrow != null)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow);
+ }
+ }
+
+ /**
+ * Returns whether a bundle is persistently started; this is an
+ * method implementation for the Start Level service.
+ * @param bundle The bundle to examine.
+ * @return <tt>true</tt> if the bundle is marked as persistently
+ * started, <tt>false</tt> otherwise.
+ * @throws java.lang.IllegalArgumentException If the specified
+ * bundle has been uninstalled.
+ **/
+ protected boolean isBundlePersistentlyStarted(Bundle bundle)
+ {
+ if (bundle.getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalArgumentException("Bundle is uninstalled.");
+ }
+
+ return (((FelixBundle) bundle).getInfo().getPersistentState() == Bundle.ACTIVE);
+ }
+
+ //
+ // Implementation of Bundle interface methods.
+ //
+
+ /**
+ * Implementation for Bundle.getSymbolicName().
+ **/
+ protected String getBundleSymbolicName(FelixBundle bundle)
+ {
+ return (String) bundle.getInfo().getCurrentHeader().get(Constants.BUNDLE_SYMBOLICNAME);
+ }
+
+ /**
+ * Get bundle headers and resolve any localized strings from resource bundles.
+ * @param bundle
+ * @param locale
+ * @return localized bundle headers dictionary.
+ **/
+ protected Dictionary getBundleHeaders(FelixBundle bundle, String locale)
+ {
+ return new MapToDictionary(bundle.getInfo().getCurrentLocalizedHeader(locale));
+ }
+
+ /**
+ * Implementation for Bundle.getLocation().
+ **/
+ protected String getBundleLocation(FelixBundle bundle)
+ {
+ return bundle.getInfo().getLocation();
+ }
+
+ /**
+ * Implementation for Bundle.getResource().
+ **/
+ protected URL getBundleResource(FelixBundle bundle, String name)
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+ return bundle.getInfo().getCurrentModule().getResource(name);
+ }
+
+ /**
+ * Implementation for Bundle.getResources().
+ **/
+ protected Enumeration getBundleResources(FelixBundle bundle, String name)
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+ return bundle.getInfo().getCurrentModule().getResources(name);
+ }
+
+ /**
+ * Implementation for Bundle.getEntry().
+ **/
+ protected URL getBundleEntry(FelixBundle bundle, String name)
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+ return bundle.getInfo().getCurrentModule()
+ .getContentLoader().getResourceFromContent(name);
+ }
+
+ /**
+ * Implementation for Bundle.getEntryPaths().
+ **/
+ protected Enumeration getBundleEntryPaths(FelixBundle bundle, String path)
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+
+ // Get the entry enumeration from the module content and
+ // create a wrapper enumeration to filter it.
+ Enumeration enumeration = new GetEntryPathsEnumeration(bundle, path);
+
+ // Return the enumeration if it has elements.
+ return (!enumeration.hasMoreElements()) ? null : enumeration;
+ }
+
+ /**
+ * Implementation for findEntries().
+ **/
+ protected Enumeration findBundleEntries(
+ FelixBundle bundle, String path, String filePattern, boolean recurse)
+ {
+ // Try to resolve the bundle per the spec.
+ resolveBundles(new Bundle[] { bundle });
+
+ // Get the entry enumeration from the module content and
+ // create a wrapper enumeration to filter it.
+ Enumeration enumeration =
+ new FindEntriesEnumeration(bundle, path, filePattern, recurse);
+
+ // Return the enumeration if it has elements.
+ return (!enumeration.hasMoreElements()) ? null : enumeration;
+ }
+
+ protected ServiceReference[] getBundleRegisteredServices(FelixBundle bundle)
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+
+ // Filter list of registered service references.
+ ServiceReference[] refs = m_registry.getRegisteredServices(bundle);
+
+ return refs;
+ }
+
+ protected ServiceReference[] getBundleServicesInUse(Bundle bundle)
+ {
+ // Filter list of "in use" service references.
+ ServiceReference[] refs = m_registry.getServicesInUse(bundle);
+
+ return refs;
+ }
+
+ protected boolean bundleHasPermission(FelixBundle bundle, Object obj)
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+
+ if (System.getSecurityManager() != null)
+ {
+ try
+ {
+ return (obj instanceof java.security.Permission)
+ ? impliesBundlePermission(
+ (BundleProtectionDomain)
+ bundle.getInfo().getProtectionDomain(),
+ (java.security.Permission) obj, true)
+ : false;
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(
+ Logger.LOG_WARNING,
+ "Exception while evaluating the permission.",
+ ex);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Implementation for Bundle.loadClass().
+ **/
+ protected Class loadBundleClass(FelixBundle bundle, String name) throws ClassNotFoundException
+ {
+ if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("Bundle is uninstalled");
+ }
+ else if (bundle.getInfo().getState() == Bundle.INSTALLED)
+ {
+ try
+ {
+ _resolveBundle(bundle);
+ }
+ catch (BundleException ex)
+ {
+ // The spec says we must fire a framework error.
+ fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
+ // Then throw a class not found exception.
+ throw new ClassNotFoundException(name);
+ }
+ }
+ Class clazz = bundle.getInfo().getCurrentModule().getClass(name);
+ if (clazz == null)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ return clazz;
+ }
+
+ /**
+ * Implementation for Bundle.start().
+ **/
+ protected void startBundle(FelixBundle bundle, boolean record)
+ throws BundleException
+ {
+ // CONCURRENCY NOTE:
+ // Starting a bundle may actually impact many bundles, since
+ // the bundle being started my need to be resolved, which in
+ // turn may need to resolve other bundles. Despite this fact,
+ // we only acquire the lock for the bundle being started, because
+ // when resolve is called on this bundle, it will eventually
+ // call resolve on the module loader search policy, which does
+ // its own locking on the module factory instance. Since the
+ // resolve algorithm is locking the module factory instance, it
+ // is not possible for other bundles to be installed or removed,
+ // so we don't have to worry about these possibilities.
+ //
+ // Further, if other bundles are started during this operation,
+ // then either they will resolve first because they got the lock
+ // on the module factory or we will resolve first since we got
+ // the lock on the module factory, so there should be no interference.
+ // If other bundles are stopped or uninstalled, this should pose
+ // no problems, since this does not impact their resolved state.
+ // If a refresh occurs, then the refresh algorithm ulimately has
+ // to acquire the module factory instance lock too before it can
+ // completely purge old modules, so it should also complete either
+ // before or after this bundle is started. At least that's the
+ // theory.
+
+ // Acquire bundle lock.
+ acquireBundleLock(bundle);
+
+ try
+ {
+ _startBundle(bundle, record);
+ }
+ finally
+ {
+ // Release bundle lock.
+ releaseBundleLock(bundle);
+ }
+ }
+
+ private void _startBundle(FelixBundle bundle, boolean record)
+ throws BundleException
+ {
+ // The spec doesn't say whether it is possible to start an extension
+ // We just do nothing
+ if (bundle.getInfo().isExtension())
+ {
+ return;
+ }
+
+ // Set and save the bundle's persistent state to active
+ // if we are supposed to record state change.
+ if (record)
+ {
+ bundle.getInfo().setPersistentStateActive();
+ }
+
+ // Try to start the bundle.
+ BundleInfo info = bundle.getInfo();
+
+ // Ignore bundles whose persistent state is not active
+ // or whose start level is greater than the framework's.
+ if ((info.getPersistentState() != Bundle.ACTIVE)
+ || (info.getStartLevel(getInitialBundleStartLevel()) > getStartLevel()))
+ {
+ return;
+ }
+
+ switch (info.getState())
+ {
+ case Bundle.UNINSTALLED:
+ throw new IllegalStateException("Cannot start an uninstalled bundle.");
+ case Bundle.STARTING:
+ case Bundle.STOPPING:
+ throw new BundleException("Starting a bundle that is starting or stopping is currently not supported.");
+ case Bundle.ACTIVE:
+ return;
+ case Bundle.INSTALLED:
+ _resolveBundle(bundle);
+ // No break.
+ case Bundle.RESOLVED:
+ info.setState(Bundle.STARTING);
+ fireBundleEvent(BundleEvent.STARTING, bundle);
+ break;
+ }
+
+ try
+ {
+ // Set the bundle's context.
+ info.setBundleContext(new BundleContextImpl(m_logger, this, bundle));
+
+ // Set the bundle's activator.
+ info.setActivator(createBundleActivator(bundle.getInfo()));
+
+ // Activate the bundle if it has an activator.
+ if (bundle.getInfo().getActivator() != null)
+ {
+ m_secureAction.startActivator(info.getActivator(),info.getBundleContext());
+ }
+
+ // TODO: CONCURRENCY - Reconsider firing event outside of the
+ // bundle lock.
+ info.setState(Bundle.ACTIVE);
+ fireBundleEvent(BundleEvent.STARTED, bundle);
+ }
+ catch (Throwable th)
+ {
+ // If there was an error starting the bundle,
+ // then reset its state to RESOLVED.
+ info.setState(Bundle.RESOLVED);
+
+ // Clean up the bundle context.
+ ((BundleContextImpl) info.getBundleContext()).invalidate();
+ info.setBundleContext(null);
+
+ // Unregister any services offered by this bundle.
+ m_registry.unregisterServices(bundle);
+
+ // Release any services being used by this bundle.
+ m_registry.ungetServices(bundle);
+
+ // Remove any listeners registered by this bundle.
+ m_dispatcher.removeListeners(bundle);
+
+ // The spec says to expect BundleException or
+ // SecurityException, so rethrow these exceptions.
+ if (th instanceof BundleException)
+ {
+ throw (BundleException) th;
+ }
+ else if (th instanceof SecurityException)
+ {
+ throw (SecurityException) th;
+ }
+ else if ((System.getSecurityManager() != null) &&
+ (th instanceof java.security.PrivilegedActionException))
+ {
+ th = ((java.security.PrivilegedActionException) th).getException();
+ }
+
+ // Rethrow all other exceptions as a BundleException.
+ throw new BundleException("Activator start error.", th);
+ }
+ }
+
+ protected void _resolveBundle(FelixBundle bundle)
+ throws BundleException
+ {
+ if (bundle.getInfo().isExtension())
+ {
+ return;
+ }
+ // If a security manager is installed, then check for permission
+ // to import the necessary packages.
+ if (System.getSecurityManager() != null)
+ {
+ BundleProtectionDomain pd = (BundleProtectionDomain)
+ bundle.getInfo().getProtectionDomain();
+
+ IRequirement[] imports =
+ bundle.getInfo().getCurrentModule().getDefinition().getRequirements();
+
+/*
+ TODO: RB - We need to fix this import check by looking at the wire
+ associated with it, not the import since we don't know the
+ package name associated with the import since it is a filter.
+
+ for (int i = 0; i < imports.length; i++)
+ {
+ if (imports[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ PackagePermission perm = new PackagePermission(
+ imports[i].???,
+ PackagePermission.IMPORT);
+
+ if (!pd.impliesDirect(perm))
+ {
+ throw new java.security.AccessControlException(
+ "PackagePermission.IMPORT denied for import: " +
+ imports[i].getName(), perm);
+ }
+ }
+ }
+*/
+ // Check export permission for all exports of the current module.
+ ICapability[] exports =
+ bundle.getInfo().getCurrentModule().getDefinition().getCapabilities();
+ for (int i = 0; i < exports.length; i++)
+ {
+ if (exports[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ PackagePermission perm = new PackagePermission(
+ (String) exports[i].getProperties().get(ICapability.PACKAGE_PROPERTY), PackagePermission.EXPORT);
+
+ if (!pd.impliesDirect(perm))
+ {
+ throw new java.security.AccessControlException(
+ "PackagePermission.EXPORT denied for export: " +
+ exports[i].getProperties().get(ICapability.PACKAGE_PROPERTY), perm);
+ }
+ }
+ }
+ }
+
+ verifyExecutionEnvironment(bundle);
+
+ IModule module = bundle.getInfo().getCurrentModule();
+ try
+ {
+ m_policyCore.resolve(module);
+ }
+ catch (ResolveException ex)
+ {
+ if (ex.getModule() != null)
+ {
+ throw new BundleException(
+ "Unresolved package in bundle "
+ + Util.getBundleIdFromModuleId(ex.getModule().getId())
+ + ": " + ex.getRequirement());
+ }
+ else
+ {
+ throw new BundleException(ex.getMessage());
+ }
+ }
+ }
+
+ protected void updateBundle(FelixBundle bundle, InputStream is)
+ throws BundleException
+ {
+ // Acquire bundle lock.
+ acquireBundleLock(bundle);
+
+ try
+ {
+ _updateBundle(bundle, is);
+ }
+ finally
+ {
+ // Release bundle lock.
+ releaseBundleLock(bundle);
+ }
+ }
+
+ protected void _updateBundle(FelixBundle bundle, InputStream is)
+ throws BundleException
+ {
+ // We guarantee to close the input stream, so put it in a
+ // finally clause.
+
+ try
+ {
+ // Variable to indicate whether bundle is active or not.
+ Throwable rethrow = null;
+
+ // Cannot update an uninstalled bundle.
+ BundleInfo info = bundle.getInfo();
+ if (info.getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+
+ // First get the update-URL from our header.
+ String updateLocation = (String)
+ info.getCurrentHeader().get(Constants.BUNDLE_UPDATELOCATION);
+
+ // If no update location specified, use original location.
+ if (updateLocation == null)
+ {
+ updateLocation = info.getLocation();
+ }
+
+ // Stop the bundle, but do not change the persistent state.
+ stopBundle(bundle, false);
+
+ try
+ {
+ // Get the bundle's archive.
+ BundleArchive archive = m_cache.getArchive(info.getBundleId());
+ // Update the bundle; this operation will increase
+ // the revision count for the bundle.
+ archive.revise(updateLocation, is);
+ // Create a module for the new revision; the revision is
+ // base zero, so subtract one from the revision count to
+ // get the revision of the new update.
+ try
+ {
+ Object sm = System.getSecurityManager();
+
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(
+ new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+ }
+
+ // We need to check whether this is an update to an
+ // extension bundle (info.isExtension) or an update from
+ // a normal bundle to an extension bundle
+ // (isExtensionBundle())
+ IModule module = createModule(
+ info.getBundleId(),
+ archive.getRevisionCount() - 1,
+ info.getCurrentHeader(),
+ (bundle.getInfo().isExtension() ||
+ m_extensionManager.isExtensionBundle(
+ bundle.getInfo().getCurrentHeader())));
+
+ // Add module to bundle info.
+ info.addModule(module);
+
+ // If this is an update from a normal to an extension bundle
+ // then attach the extension or else if this already is
+ // an extension bundle then dont allow it to be resolved
+ // again as per spec.
+ if (!bundle.getInfo().isExtension() &&
+ m_extensionManager.isExtensionBundle(bundle.getInfo().getCurrentHeader()))
+ {
+ addSecurity(bundle);
+ m_extensionManager.addExtensionBundle(this, bundle);
+ m_factory.refreshModule(m_systemBundleInfo.getCurrentModule());
+ bundle.getInfo().setState(Bundle.RESOLVED);
+ }
+ else if (bundle.getInfo().isExtension())
+ {
+ bundle.getInfo().setState(Bundle.INSTALLED);
+ }
+ else
+ {
+ addSecurity(bundle);
+ }
+ }
+ catch (Throwable ex)
+ {
+ try
+ {
+ archive.undoRevise();
+ }
+ catch (Exception busted)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Unable to rollback.", busted);
+ }
+
+ throw ex;
+ }
+ }
+ catch (Throwable ex)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
+ rethrow = ex;
+ }
+
+ // Set new state, mark as needing a refresh, and fire updated event
+ // if successful.
+ if (rethrow == null)
+ {
+ info.setLastModified(System.currentTimeMillis());
+
+ if (!info.isExtension())
+ {
+ info.setState(Bundle.INSTALLED);
+ }
+
+ fireBundleEvent(BundleEvent.UNRESOLVED, bundle);
+
+ // Mark previous the bundle's old module for removal since
+ // it can no longer be used to resolve other modules per the spec.
+ ((ModuleImpl) info.getModules()[info.getModules().length - 2])
+ .setRemovalPending(true);
+
+ fireBundleEvent(BundleEvent.UPDATED, bundle);
+
+ // Determine if the bundle is in use by anyone.
+ boolean used = false;
+ IModule[] modules = info.getModules();
+ for (int i = 0; !used && (i < modules.length); i++)
+ {
+ IModule[] dependents = ((ModuleImpl) modules[i]).getDependents();
+ for (int j = 0; (dependents != null) && (j < dependents.length) && !used; j++)
+ {
+ if (dependents[j] != modules[i])
+ {
+ used = true;
+ }
+ }
+ }
+
+ // If the bundle is not used by anyone, then garbage
+ // collect it now.
+ if (!used)
+ {
+ try
+ {
+ refreshPackages(new Bundle[] { bundle });
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to immediately purge the bundle revisions.", ex);
+ }
+ }
+ }
+
+ // Restart bundle, but do not change the persistent state.
+ // This will not start the bundle if it was not previously
+ // active.
+ startBundle(bundle, false);
+
+ // If update failed, rethrow exception.
+ if (rethrow != null)
+ {
+ if ((System.getSecurityManager() != null) &&
+ (rethrow instanceof SecurityException))
+ {
+ throw (SecurityException) rethrow;
+ }
+
+ throw new BundleException("Update failed.", rethrow);
+ }
+ }
+ finally
+ {
+ try
+ {
+ if (is != null) is.close();
+ }
+ catch (IOException ex)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
+ }
+ }
+ }
+
+ protected void stopBundle(FelixBundle bundle, boolean record)
+ throws BundleException
+ {
+ // Acquire bundle lock.
+ acquireBundleLock(bundle);
+
+ try
+ {
+ _stopBundle(bundle, record);
+ }
+ finally
+ {
+ // Always release bundle lock.
+ releaseBundleLock(bundle);
+ }
+ }
+
+ private void _stopBundle(FelixBundle bundle, boolean record)
+ throws BundleException
+ {
+ Throwable rethrow = null;
+
+ // Set the bundle's persistent state to inactive if necessary.
+ if (record)
+ {
+ bundle.getInfo().setPersistentStateInactive();
+ }
+
+ BundleInfo info = bundle.getInfo();
+
+ switch (info.getState())
+ {
+ case Bundle.UNINSTALLED:
+ throw new IllegalStateException("Cannot stop an uninstalled bundle.");
+ case Bundle.STARTING:
+ case Bundle.STOPPING:
+ throw new BundleException("Stopping a bundle that is starting or stopping is currently not supported.");
+ case Bundle.INSTALLED:
+ case Bundle.RESOLVED:
+ return;
+ case Bundle.ACTIVE:
+ // Set bundle state..
+ info.setState(Bundle.STOPPING);
+ fireBundleEvent(BundleEvent.STOPPING, bundle);
+ break;
+ }
+
+ try
+ {
+ if (info.getActivator() != null)
+ {
+ m_secureAction.stopActivator(info.getActivator(), info.getBundleContext());
+ }
+
+ // Try to save the activator in the cache.
+ // NOTE: This is non-standard OSGi behavior and only
+ // occurs if strictness is disabled.
+ String strict = (String) m_configMap.get(FelixConstants.STRICT_OSGI_PROP);
+ boolean isStrict = (strict == null) ? true : strict.equals("true");
+ if (!isStrict)
+ {
+ try
+ {
+ m_cache.getArchive(info.getBundleId())
+ .setActivator(info.getActivator());
+ }
+ catch (Exception ex)
+ {
+ // Problem saving activator, so ignore it.
+ // TODO: FRAMEWORK - Perhaps we should handle this some other way?
+ }
+ }
+ }
+ catch (Throwable th)
+ {
+ m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
+ rethrow = th;
+ }
+
+ // Do not clean up after the system bundle since it will
+ // clean up after itself.
+ if (info.getBundleId() != 0)
+ {
+ // Clean up the bundle context.
+ ((BundleContextImpl) info.getBundleContext()).invalidate();
+ info.setBundleContext(null);
+
+ // Unregister any services offered by this bundle.
+ m_registry.unregisterServices(bundle);
+
+ // Release any services being used by this bundle.
+ m_registry.ungetServices(bundle);
+
+ // The spec says that we must remove all event
+ // listeners for a bundle when it is stopped.
+ m_dispatcher.removeListeners(bundle);
+
+ info.setState(Bundle.RESOLVED);
+ fireBundleEvent(BundleEvent.STOPPED, bundle);
+ }
+
+ // Throw activator error if there was one.
+ if (rethrow != null)
+ {
+ // The spec says to expect BundleException or
+ // SecurityException, so rethrow these exceptions.
+ if (rethrow instanceof BundleException)
+ {
+ throw (BundleException) rethrow;
+ }
+ else if (rethrow instanceof SecurityException)
+ {
+ throw (SecurityException) rethrow;
+ }
+ else if ((System.getSecurityManager() != null) &&
+ (rethrow instanceof java.security.PrivilegedActionException))
+ {
+ rethrow = ((java.security.PrivilegedActionException) rethrow).getException();
+ }
+
+ // Rethrow all other exceptions as a BundleException.
+ throw new BundleException("Activator stop error.", rethrow);
+ }
+ }
+
+ protected void uninstallBundle(FelixBundle bundle) throws BundleException
+ {
+ // Acquire bundle lock.
+ acquireBundleLock(bundle);
+
+ try
+ {
+ _uninstallBundle(bundle);
+ }
+ finally
+ {
+ // Always release bundle lock.
+ releaseBundleLock(bundle);
+ }
+ }
+
+ private void _uninstallBundle(FelixBundle bundle) throws BundleException
+ {
+ BundleInfo info = bundle.getInfo();
+ if (info.getState() == Bundle.UNINSTALLED)
+ {
+ throw new IllegalStateException("The bundle is uninstalled.");
+ }
+
+ // Extension Bundles are not removed until the framework is shutdown
+ if (bundle.getInfo().isExtension())
+ {
+ bundle.getInfo().setPersistentStateUninstalled();
+ bundle.getInfo().setState(Bundle.INSTALLED);
+ return;
+ }
+
+ // The spec says that uninstall should always succeed, so
+ // catch an exception here if stop() doesn't succeed and
+ // rethrow it at the end.
+ try
+ {
+ stopBundle(bundle, true);
+ }
+ catch (BundleException ex)
+ {
+ fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
+ }
+
+ // Remove the bundle from the installed map.
+ FelixBundle target = null;
+ synchronized (m_installedBundleLock_Priority2)
+ {
+ target = (FelixBundle) m_installedBundleMap.remove(info.getLocation());
+ m_installedBundleIndex.remove(new Long(target.getBundleId()));
+ }
+
+ // Finally, put the uninstalled bundle into the
+ // uninstalled list for subsequent refreshing.
+ if (target != null)
+ {
+ // Set the bundle's persistent state to uninstalled.
+ target.getInfo().setPersistentStateUninstalled();
+
+ // Mark current module for removal since it can no longer
+ // be used to resolve other modules per the spec.
+ ((ModuleImpl) target.getInfo().getCurrentModule()).setRemovalPending(true);
+
+ // Put bundle in uninstalled bundle array.
+ rememberUninstalledBundle(bundle);
+ }
+ else
+ {
+ m_logger.log(
+ Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
+ }
+
+ // Set state to uninstalled.
+ info.setState(Bundle.UNINSTALLED);
+ info.setLastModified(System.currentTimeMillis());
+
+ // Fire bundle event.
+ fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
+
+ // Determine if the bundle is in use by anyone.
+ boolean used = false;
+ IModule[] modules = info.getModules();
+ for (int i = 0; !used && (i < modules.length); i++)
+ {
+ IModule[] dependents = ((ModuleImpl) modules[i]).getDependents();
+ for (int j = 0; (dependents != null) && (j < dependents.length) && !used; j++)
+ {
+ if (dependents[j] != modules[i])
+ {
+ used = true;
+ }
+ }
+ }
+
+ // If the bundle is not used by anyone, then garbage
+ // collect it now.
+ if (!used)
+ {
+ try
+ {
+ refreshPackages(new Bundle[] { bundle });
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to immediately garbage collect the bundle.", ex);
+ }
+ }
+ }
+
+ //
+ // Implementation of BundleContext interface methods.
+ //
+
+ protected void addRequirement(FelixBundle bundle, String s) throws BundleException
+ {
+ // TODO: EXPERIMENTAL - Experimental implicit wire concept to try
+ // to deal with code generation.
+ synchronized (m_factory)
+ {
+ IRequirement[] reqs = ManifestParser.parseImportHeader(s);
+ IRequirement[] dynamics = bundle.getInfo().getCurrentModule()
+ .getDefinition().getDynamicRequirements();
+ if (dynamics == null)
+ {
+ dynamics = reqs;
+ }
+ else
+ {
+ IRequirement[] tmp = new IRequirement[dynamics.length + reqs.length];
+ System.arraycopy(dynamics, 0, tmp, 0, dynamics.length);
+ System.arraycopy(reqs, 0, tmp, dynamics.length, reqs.length);
+ dynamics = tmp;
+ }
+ ((ModuleDefinition) bundle.getInfo().getCurrentModule().getDefinition())
+ .setDynamicRequirements(dynamics);
+ }
+ }
+
+ /**
+ * Implementation for BundleContext.getProperty(). Returns
+ * environment property associated with the framework.
+ *
+ * @param key The name of the property to retrieve.
+ * @return The value of the specified property or null.
+ **/
+ protected String getProperty(String key)
+ {
+ // First, check the config properties.
+ String val = (String) m_configMap.get(key);
+ // If not found, then try the system properties.
+ return (val == null) ? System.getProperty(key) : val;
+ }
+
+ protected Bundle installBundle(String location, InputStream is)
+ throws BundleException
+ {
+ return installBundle(-1, location, is);
+ }
+
+ private Bundle installBundle(long id, String location, InputStream is)
+ throws BundleException
+ {
+ FelixBundle bundle = null;
+
+ // Acquire an install lock.
+ acquireInstallLock(location);
+
+ try
+ {
+ // Check to see if the framework is still running;
+ if ((getState() == Bundle.STOPPING) ||
+ (getState() == Bundle.UNINSTALLED))
+ {
+ throw new BundleException("The framework has been shutdown.");
+ }
+
+ // If bundle location is already installed, then
+ // return it as required by the OSGi specification.
+ bundle = (FelixBundle) getBundle(location);
+ if (bundle != null)
+ {
+ return bundle;
+ }
+
+ // Determine if this is a new or existing bundle.
+ boolean isNew = (id < 0);
+
+ // If the bundle is new we must cache its JAR file.
+ if (isNew)
+ {
+ // First generate an identifier for it.
+ id = getNextId();
+
+ try
+ {
+ // Add the bundle to the cache.
+ m_cache.create(id, location, is);
+ }
+ catch (Exception ex)
+ {
+ throw new BundleException(
+ "Unable to cache bundle: " + location, ex);
+ }
+ finally
+ {
+ try
+ {
+ if (is != null) is.close();
+ }
+ catch (IOException ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to close input stream.", ex);
+ }
+ }
+ }
+ else
+ {
+ // If the bundle we are installing is not new,
+ // then try to purge old revisions before installing
+ // it; this is done just in case a "refresh"
+ // didn't occur last session...this would only be
+ // due to an error or system crash.
+ try
+ {
+ if (m_cache.getArchive(id).getRevisionCount() > 1)
+ {
+ m_cache.getArchive(id).purge();
+ }
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Could not purge bundle.", ex);
+ }
+ }
+
+ try
+ {
+ BundleArchive archive = m_cache.getArchive(id);
+ bundle = new BundleImpl(this, createBundleInfo(archive,
+ m_extensionManager.isExtensionBundle(archive.getRevision(
+ archive.getRevisionCount() - 1).getManifestHeader())));
+
+ verifyExecutionEnvironment(bundle);
+
+ addSecurity(bundle);
+
+ if (!bundle.getInfo().isExtension())
+ {
+ Object sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(
+ new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+ }
+ }
+ else
+ {
+ m_extensionManager.addExtensionBundle(this, bundle);
+ m_factory.refreshModule(m_systemBundleInfo.getCurrentModule());
+ }
+
+ }
+ catch (Throwable ex)
+ {
+ // If the bundle is new, then remove it from the cache.
+ // TODO: FRAMEWORK - Perhaps it should be removed if it is not new too.
+ if (isNew)
+ {
+ try
+ {
+ m_cache.remove(m_cache.getArchive(id));
+ }
+ catch (Exception ex1)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Could not remove from cache.", ex1);
+ }
+ }
+
+ if (bundle != null)
+ {
+ ((ModuleImpl) bundle.getInfo().getCurrentModule()).setRemovalPending(true);
+ }
+
+ if ((System.getSecurityManager() != null) &&
[... 2073 lines stripped ...]