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 ...]