Implement the extension:=framework part of extension bundles minus the automatic framework restart (FELIX-30). 

git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@506754 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
index 93357a6..e57965f 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -67,9 +67,9 @@
     public String getProperty(String name)
     {
         checkValidity();
-        
+
         Object sm = System.getSecurityManager();
-        
+
         if (sm != null)
         {
             if (!(Constants.FRAMEWORK_VERSION.equals(name) ||
@@ -83,14 +83,14 @@
                     new java.util.PropertyPermission(name, "read"));
             }
         }
-        
+
         return m_felix.getProperty(name);
     }
 
     public Bundle getBundle()
     {
         checkValidity();
-        
+
         return m_bundle;
     }
 
@@ -98,7 +98,7 @@
         throws InvalidSyntaxException
     {
         checkValidity();
-        
+
         return new FilterImpl(m_felix.getLogger(), expr);
     }
 
@@ -112,11 +112,11 @@
         throws BundleException
     {
         checkValidity();
-        
+
         Bundle result = null;
-        
+
         Object sm = System.getSecurityManager();
-        
+
         if (sm != null)
         {
             result = m_felix.installBundle(location, is);
@@ -129,57 +129,57 @@
         {
             result = m_felix.installBundle(location, is);
         }
-        
+
         return result;
     }
 
     public Bundle getBundle(long id)
     {
         checkValidity();
-        
+
         return m_felix.getBundle(id);
     }
 
     public Bundle[] getBundles()
     {
         checkValidity();
-        
+
         return m_felix.getBundles();
     }
 
     public void addBundleListener(BundleListener l)
     {
         checkValidity();
-        
+
         Object sm = System.getSecurityManager();
-        
+
         if (sm != null)
         {
             if (l instanceof SynchronousBundleListener)
             {
-                ((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle, 
+                ((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle,
                     AdminPermission.LISTENER));
             }
         }
-        
+
         m_felix.addBundleListener(m_bundle, l);
     }
 
     public void removeBundleListener(BundleListener l)
     {
         checkValidity();
-        
+
         Object sm = System.getSecurityManager();
-        
+
         if (sm != null)
         {
             if (l instanceof SynchronousBundleListener)
             {
-                ((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle, 
+                ((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle,
                     AdminPermission.LISTENER));
             }
         }
-        
+
         m_felix.removeBundleListener(m_bundle, l);
     }
 
@@ -199,28 +199,28 @@
         throws InvalidSyntaxException
     {
         checkValidity();
-        
+
         m_felix.addServiceListener(m_bundle, l, s);
     }
 
     public void removeServiceListener(ServiceListener l)
     {
         checkValidity();
-        
+
         m_felix.removeServiceListener(m_bundle, l);
     }
 
     public void addFrameworkListener(FrameworkListener l)
     {
         checkValidity();
-        
+
         m_felix.addFrameworkListener(m_bundle, l);
     }
 
     public void removeFrameworkListener(FrameworkListener l)
     {
         checkValidity();
-        
+
         m_felix.removeFrameworkListener(m_bundle, l);
     }
 
@@ -234,9 +234,9 @@
         String[] clazzes, Object svcObj, Dictionary dict)
     {
         checkValidity();
-        
+
         Object sm = System.getSecurityManager();
-        
+
         if (sm != null)
         {
             if (clazzes != null)
@@ -244,18 +244,18 @@
                 for (int i = 0;i < clazzes.length;i++)
                 {
                     ((SecurityManager) sm).checkPermission(
-                        new ServicePermission(clazzes[i], ServicePermission.REGISTER));        
+                        new ServicePermission(clazzes[i], ServicePermission.REGISTER));
                 }
             }
         }
-        
+
         return m_felix.registerService(m_bundle, clazzes, svcObj, dict);
     }
 
     public ServiceReference getServiceReference(String clazz)
     {
         checkValidity();
-        
+
         try
         {
             ServiceReference[] refs = getServiceReferences(clazz, null);
@@ -355,7 +355,7 @@
     public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException
     {
         checkValidity();
-        
+
         return m_felix.getAllowedServiceReferences(m_bundle, clazz, filter, false);
 
     }
@@ -364,7 +364,7 @@
         throws InvalidSyntaxException
     {
         checkValidity();
-        
+
         return m_felix.getAllowedServiceReferences(m_bundle, clazz, filter, true);
 
     }
@@ -372,53 +372,53 @@
     public Object getService(ServiceReference ref)
     {
         checkValidity();
-        
+
         if (ref == null)
         {
             throw new NullPointerException("Specified service reference cannot be null.");
         }
-        
+
         Object sm = System.getSecurityManager();
-        
+
         if (sm != null)
         {
             String[] objectClass = (String[]) ref.getProperty(Constants.OBJECTCLASS);
-            
+
             if (objectClass == null)
             {
                 return null;
             }
-            
+
             boolean hasPermission = false;
-            
+
             for (int i = 0;(i < objectClass.length) && !hasPermission;i++)
             {
-                try 
+                try
                 {
                     ((SecurityManager) sm).checkPermission(
                         new ServicePermission(objectClass[i], ServicePermission.GET));
-                    
+
                     hasPermission = true;
                 }
                 catch (Exception ex)
                 {
-                    
+
                 }
             }
-            
+
             if (!hasPermission)
             {
                 throw new SecurityException("No permission");
             }
         }
-        
+
         return m_felix.getService(m_bundle, ref);
     }
 
     public boolean ungetService(ServiceReference ref)
     {
         checkValidity();
-        
+
         if (ref == null)
         {
             throw new NullPointerException("Specified service reference cannot be null.");
@@ -431,7 +431,7 @@
     public File getDataFile(String s)
     {
         checkValidity();
-        
+
         return m_felix.getDataFile(m_bundle, s);
     }
 
@@ -446,8 +446,15 @@
                 case Bundle.STOPPING:
                     return;
             }
+
+            // As an exception we allow extension bundles to use their bundle
+            // context while not being active.
+            if (m_bundle.getInfo().isExtension())
+            {
+                return;
+            }
         }
-        
+
         throw new IllegalStateException("Invalid BundleContext.");
     }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index a917ddd..eefa16c 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -408,8 +408,8 @@
         return false;
     }
 
-    String[] getSubjectDNs()
+    Object getSignerMatcher()
     {
-        return m_info.getArchive().getDNChains();
+        return null;
     }
 }
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleInfo.java b/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
index ca7737c..274b69f 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -42,6 +42,11 @@
     // been refreshed and completely removed from the framework.
     private boolean m_stale = false;
 
+    // Indicates whether the bundle is an extension, meaning that it is
+    // installed as an extension bundle to the framework (i.e., can not be
+    // removed or updated until a framework restart.
+    private boolean m_extension = false;
+
     // Used for bundle locking.
     private int m_lockCount = 0;
     private Thread m_lockThread = null;
@@ -112,7 +117,7 @@
     {
         return m_modules[m_modules.length - 1];
     }
-    
+
     /**
      * Add a module that corresponds to a new bundle JAR file revision for
      * the bundle associated with this <tt>BundleInfo</tt> object.
@@ -141,7 +146,7 @@
             return -1;
         }
     }
-    
+
     public String getLocation()
     {
         try
@@ -343,7 +348,7 @@
         }
         return result;
     }
-    
+
     public int getState()
     {
         return m_state;
@@ -475,6 +480,16 @@
         m_stale = true;
     }
 
+    public boolean isExtension()
+    {
+        return m_extension;
+    }
+
+    public void setExtension(boolean extension)
+    {
+        m_extension = extension;
+    }
+
     //
     // Locking related methods.
     // NOTE: These methods are not synchronized because it is assumed they
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 1d225f0..71e6f25 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -19,9 +19,9 @@
 package org.apache.felix.framework;
 
 import java.io.*;
-import java.net.URL;
-import java.net.URLStreamHandler;
+import java.net.*;
 import java.security.*;
+import java.security.cert.Certificate;
 import java.util.*;
 
 import org.apache.felix.framework.cache.*;
@@ -104,7 +104,7 @@
     private Set m_executionEnvironmentCache = new HashSet();
 
     // The secure action used to do privileged calls
-    private SecureAction m_secureAction = new SecureAction();
+    protected SecureAction m_secureAction = new SecureAction();
 
     private Collection m_trustedCaCerts = null;
 
@@ -213,20 +213,11 @@
     public synchronized void start(MutablePropertyResolver configMutable,
         List activatorList)
     {
-        start(configMutable, activatorList, (Collection) null);
-    }
-
-    public synchronized void start(
-        MutablePropertyResolver configMutable,
-        List activatorList, Collection trustedCaCerts)
-    {
         if (m_frameworkStatus != INITIAL_STATUS)
         {
             throw new IllegalStateException("Invalid framework status: " + m_frameworkStatus);
         }
 
-        m_trustedCaCerts = trustedCaCerts;
-
         // The framework is now in its startup sequence.
         m_frameworkStatus = STARTING_STATUS;
 
@@ -265,7 +256,7 @@
 
         try
         {
-            m_cache = new BundleCache(m_config, m_logger, m_trustedCaCerts);
+            m_cache = new BundleCache(m_config, m_logger);
         }
         catch (Exception ex)
         {
@@ -362,10 +353,8 @@
             BundleInfo info = new BundleInfo(
                 m_logger, new SystemBundleArchive(), null);
             systembundle = new SystemBundle(this, info, activatorList);
-            // Create a module for the system bundle.
-            IModuleDefinition md = new ModuleDefinition(
-                systembundle.getExports(), null, null, null);
-            systembundle.getInfo().addModule(m_factory.createModule("0", md));
+            systembundle.getInfo().addModule(m_factory.createModule("0",
+                systembundle));
             systembundle.getContentLoader().setSearchPolicy(
                 new R4SearchPolicy(
                     m_policyCore, systembundle.getInfo().getCurrentModule()));
@@ -559,7 +548,7 @@
             fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
             m_logger.log(Logger.LOG_ERROR, "Error stopping framework.", ex);
         }
-        
+
         // Finally shutdown the JVM if the framework is running stand-alone.
         String embedded = m_config.get(FelixConstants.EMBEDDED_EXECUTION_PROP);
         boolean isEmbedded = (embedded == null) ? false : embedded.equals("true");
@@ -568,7 +557,7 @@
             m_secureAction.exit(0);
         }
     }
-    
+
     /**
      * This method actually performs the real shutdown operations of the
      * framework in terms of setting the start level to zero, really stopping
@@ -1248,6 +1237,13 @@
     private void _startBundle(BundleImpl 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)
@@ -1369,7 +1365,7 @@
                     PackagePermission perm = new PackagePermission(
                         imports[i].???,
                         PackagePermission.IMPORT);
-    
+
                     if (!pd.implies(perm))
                     {
                         throw new java.security.AccessControlException(
@@ -1388,7 +1384,7 @@
                 {
                     PackagePermission perm = new PackagePermission(
                         (String) exports[i].getProperties().get(ICapability.PACKAGE_PROPERTY), PackagePermission.EXPORT);
-    
+
                     if (!pd.implies(perm))
                     {
                         throw new java.security.AccessControlException(
@@ -1400,7 +1396,7 @@
         }
 
         verifyExecutionEnvironment(bundle);
-        
+
         IModule module = bundle.getInfo().getCurrentModule();
         try
         {
@@ -1448,7 +1444,7 @@
         try
         {
             // Variable to indicate whether bundle is active or not.
-            Exception rethrow = null;
+            Throwable rethrow = null;
 
             // Cannot update an uninstalled bundle.
             BundleInfo info = bundle.getInfo();
@@ -1482,11 +1478,6 @@
                 // get the revision of the new update.
                 try
                 {
-                    IModule module = createModule(
-                        info.getBundleId(),
-                        archive.getRevisionCount() - 1,
-                        info.getCurrentHeader());
-
                     Object sm = System.getSecurityManager();
 
                     if (sm != null)
@@ -1495,10 +1486,37 @@
                             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(),
+                        createBundleProtectionDomain(archive),
+                        bundle.getInfo().isExtension() || 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 done allow it to be resolved 
+                    // again as per spec.
+                    if (!bundle.getInfo().isExtension() &&
+                        isExtensionBundle(bundle.getInfo().getCurrentHeader()))
+                    {
+                        attachExtensionBundle(bundle);
+                        bundle.getInfo().setState(BundleImpl.RESOLVED);
+                    }
+                    else if (bundle.getInfo().isExtension())
+                    {
+                        bundle.getInfo().setState(BundleImpl.INSTALLED);
+                    }
                 }
-                catch (Exception ex)
+                catch (Throwable ex)
                 {
                     try
                     {
@@ -1512,7 +1530,7 @@
                     throw ex;
                 }
             }
-            catch (Exception ex)
+            catch (Throwable ex)
             {
                 m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
                 rethrow = ex;
@@ -1523,7 +1541,12 @@
             if (rethrow == null)
             {
                 info.setLastModified(System.currentTimeMillis());
-                info.setState(Bundle.INSTALLED);
+
+                if (!info.isExtension())
+                {
+                    info.setState(Bundle.INSTALLED);
+                }
+
                 fireBundleEvent(BundleEvent.UNRESOLVED, bundle);
 
                 // Mark previous the bundle's old module for removal since
@@ -1740,6 +1763,14 @@
             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.
@@ -1771,7 +1802,7 @@
             ((ModuleImpl) target.getInfo().getCurrentModule()).setRemovalPending(true);
 
             // Put bundle in uninstalled bundle array.
-            rememberUninstalledBundle(bundle);               
+            rememberUninstalledBundle(bundle);
         }
         else
         {
@@ -1926,17 +1957,28 @@
             try
             {
                 BundleArchive archive = m_cache.getArchive(id);
-                bundle = new BundleImpl(this, createBundleInfo(archive));
+                bundle = new BundleImpl(this, createBundleInfo(archive,
+                    isExtensionBundle(archive.getRevision(
+                    archive.getRevisionCount() - 1).getManifestHeader())));
+
                 verifyExecutionEnvironment(bundle);
 
-                Object sm = System.getSecurityManager();
-                if (sm != null)
+                if (!bundle.getInfo().isExtension())
                 {
-                    ((SecurityManager) sm).checkPermission(
-                        new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+                    Object sm = System.getSecurityManager();
+                    if (sm != null)
+                    {
+                        ((SecurityManager) sm).checkPermission(
+                            new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+                    }
                 }
+                else
+                {
+                    attachExtensionBundle(bundle);
+                }
+
             }
-            catch (Exception ex)
+            catch (Throwable ex)
             {
                 // If the bundle is new, then remove it from the cache.
                 // TODO: Perhaps it should be removed if it is not new too.
@@ -1954,12 +1996,19 @@
                     }
                 }
 
+                if (bundle != null)
+                {
+                    ((ModuleImpl) bundle.getInfo().getCurrentModule()).setRemovalPending(true);
+                }
+
                 if ((System.getSecurityManager() != null) &&
                     (ex instanceof SecurityException))
                 {
                     throw (SecurityException) ex;
                 }
 
+                ex.printStackTrace();
+
                 throw new BundleException("Could not create bundle object.", ex);
             }
 
@@ -2003,6 +2052,68 @@
         return bundle;
     }
 
+    private boolean isExtensionBundle(Map headers)
+    {
+        R4Directive dir = ManifestParser.parseExtensionBundleHeader((String)
+            headers.get(Constants.FRAGMENT_HOST));
+
+        return (dir != null) && (Constants.EXTENSION_FRAMEWORK.equals(
+            dir.getValue()) || Constants.EXTENSION_BOOTCLASSPATH.equals(
+            dir.getValue()));
+    }
+
+    private void attachExtensionBundle(BundleImpl bundle) throws Exception
+    {
+        Object sm = System.getSecurityManager();
+        if (sm != null)
+        {
+            ((SecurityManager) sm).checkPermission(
+                new AdminPermission(bundle, AdminPermission.EXTENSIONLIFECYCLE));
+        }
+
+        ProtectionDomain pd = (ProtectionDomain)
+        bundle.getInfo().getCurrentModule().getSecurityContext();
+
+        if (pd != null)
+        {
+            if (!pd.implies(new AllPermission()))
+            {
+                throw new SecurityException("Extension Bundles must have AllPermission");
+            }
+        }
+
+        R4Directive dir = ManifestParser.parseExtensionBundleHeader((String)
+            bundle.getInfo().getCurrentHeader().get(Constants.FRAGMENT_HOST));
+
+        if (!Constants.EXTENSION_FRAMEWORK.equals(dir.getValue()))
+        {
+            throw new BundleException("Unsupported Extension Bundle type: " +
+                dir.getValue(), new UnsupportedOperationException(
+                "Unsupported Extension Bundle type!"));
+        }
+
+        BundleImpl systemBundle = (BundleImpl) getBundle(0);
+        acquireBundleLock(systemBundle);
+
+        try
+        {
+            bundle.getInfo().setExtension(true);
+
+            ((SystemBundle) getBundle(0)).addExtensionBundle(bundle);
+        }
+        catch (Exception ex)
+        {
+            bundle.getInfo().setExtension(false);
+            throw ex;
+        }
+        finally
+        {
+            releaseBundleLock(systemBundle);
+        }
+
+        bundle.getInfo().setState(Bundle.RESOLVED);
+    }
+
     /**
      * Checks the passed in bundle and checks to see if there is a required execution environment.
      * If there is, it gets the execution environment string and verifies that the framework provides it.
@@ -2037,7 +2148,7 @@
      *         False if none of the provided framework execution environments match
     **/
     private boolean isMatchingExecutionEnvironment(String bundleEnvironment)
-    { 
+    {
         String frameworkEnvironment = getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
         if (frameworkEnvironment == null)
         {
@@ -2491,9 +2602,11 @@
         // The spec says to throw an error if the bundle
         // is stopped, which I assume means not active,
         // starting, or stopping.
+        // Additionally, we make an exception for extension bundles
         if ((bundle.getInfo().getState() != Bundle.ACTIVE) &&
             (bundle.getInfo().getState() != Bundle.STARTING) &&
-            (bundle.getInfo().getState() != Bundle.STOPPING))
+            (bundle.getInfo().getState() != Bundle.STOPPING) &&
+            !bundle.getInfo().isExtension())
         {
             throw new IllegalStateException("Only active bundles can create files.");
         }
@@ -2692,7 +2805,7 @@
                                 null,
                                 null,
                                 new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, ((Capability) caps[capIdx]).getPackageName(), false) }));
-    
+
                         // Search through the current providers to find the target
                         // module.
                         for (int i = 0; (inUseModules != null) && (i < inUseModules.length); i++)
@@ -2795,6 +2908,39 @@
         // Acquire locks for all impacted bundles.
         BundleImpl[] bundles = acquireBundleRefreshLocks(targets);
 
+        boolean restart = false;
+        
+        Bundle systemBundle = getBundle(0);
+
+        // We need to restart the framework if either an extension bundle is
+        // refreshed or the system bundle is refreshed and any extension bundle
+        // has been updated or uninstalled.
+        for (int i = 0; (bundles != null) && !restart && (i < bundles.length); i++)
+        {
+            if (bundles[i].getInfo().isExtension())
+            {
+                restart = true;
+            }
+            else if (systemBundle == bundles[i])
+            {
+                Bundle[] allBundles = getBundles();
+                for (int j = 0; !restart && j < allBundles.length; j++)
+                {
+                    if (((BundleImpl) allBundles[j]).getInfo().isExtension() &&
+                        (allBundles[j].getState() == BundleImpl.INSTALLED))
+                    {
+                        restart = true;
+                    }
+                }
+            }
+        }
+
+        if (restart)
+        {
+// TODO: Extension Bundle - We need a way to restart the framework
+            m_logger.log(Logger.LOG_WARNING, "Framework restart not implemented.");
+        }
+
         // Remove any targeted bundles from the uninstalled bundles
         // array, since they will be removed from the system after
         // the refresh.
@@ -2816,21 +2962,30 @@
                 RefreshHelper[] helpers = new RefreshHelper[bundles.length];
                 for (int i = 0; i < bundles.length; i++)
                 {
-                    helpers[i] = new RefreshHelper(bundles[i]);
+                    if (!bundles[i].getInfo().isExtension())
+                    {
+                        helpers[i] = new RefreshHelper(bundles[i]);
+                    }
                 }
 
                 // Stop, purge or remove, and reinitialize all bundles first.
                 for (int i = 0; i < helpers.length; i++)
                 {
-                    helpers[i].stop();
-                    helpers[i].purgeOrRemove();
-                    helpers[i].reinitialize();
+                    if (helpers[i] != null)
+                    {
+                        helpers[i].stop();
+                        helpers[i].purgeOrRemove();
+                        helpers[i].reinitialize();
+                    }
                 }
 
                 // Then restart all bundles that were previously running.
                 for (int i = 0; i < helpers.length; i++)
                 {
-                    helpers[i].restart();
+                    if (helpers[i] != null)
+                    {
+                        helpers[i].restart();
+                    }
                 }
             }
         }
@@ -2874,7 +3029,7 @@
     // Miscellaneous private methods.
     //
 
-    private BundleInfo createBundleInfo(BundleArchive archive)
+    private BundleInfo createBundleInfo(BundleArchive archive, boolean isExtension)
         throws Exception
     {
         // Get the bundle manifest.
@@ -2900,10 +3055,30 @@
         // ever be one revision at this point, create the module for
         // the current revision to be safe.
         IModule module = createModule(
-            archive.getId(), archive.getRevisionCount() - 1, headerMap);
+            archive.getId(), archive.getRevisionCount() - 1, headerMap,
+            createBundleProtectionDomain(archive), isExtension);
 
         // Finally, create an return the bundle info.
-        return new BundleInfo(m_logger, archive, module);
+        BundleInfo info = new BundleInfo(m_logger, archive, module);
+        info.setExtension(isExtension);
+
+        return info;
+    }
+
+    private ProtectionDomain createBundleProtectionDomain(BundleArchive archive)
+        throws Exception
+    {
+//      TODO: Security - create a real ProtectionDomain for the Bundle
+        FakeURLStreamHandler handler = new FakeURLStreamHandler();
+        URL context = new URL(null, "location:", handler);
+        CodeSource codesource = new CodeSource(m_secureAction.createURL(context,
+            archive.getLocation(), handler), (Certificate[]) null);
+
+        Permissions allPerms = new Permissions();
+        allPerms.add(new AllPermission());
+        ProtectionDomain pd = new ProtectionDomain(codesource,
+            allPerms);
+        return pd;
     }
 
     /**
@@ -2915,7 +3090,8 @@
      * @param headerMap The headers map associated with the bundle.
      * @return The initialized and/or newly created module.
     **/
-    private IModule createModule(long targetId, int revision, Map headerMap)
+    private IModule createModule(long targetId, int revision, Map headerMap,
+        Object securityContext, boolean isExtensionBundle)
         throws Exception
     {
         ManifestParser mp = new ManifestParser(m_logger, m_config, headerMap);
@@ -2950,8 +3126,10 @@
         // pieces and bind them together.
 
         // Create the module definition for the new module.
+        // Note, in case this is an extension bundle it's exports are removed -
+        // they will be added to the system bundle directly later on.
         IModuleDefinition md = new ModuleDefinition(
-            mp.getCapabilities(),
+            (isExtensionBundle) ? null : mp.getCapabilities(),
             mp.getRequirements(),
             mp.getDynamicRequirements(),
             mp.getLibraries(m_cache.getArchive(targetId).getRevision(revision)));
@@ -2960,17 +3138,7 @@
         IModule module = m_factory.createModule(
             Long.toString(targetId) + "." + Integer.toString(revision), md);
 
-        FakeURLStreamHandler handler = new FakeURLStreamHandler();
-        URL context = new URL(null, "location:", handler);
-        CodeSource codesource = new CodeSource(m_secureAction.createURL(context, 
-            m_cache.getArchive(targetId).getLocation(), 
-            handler), 
-            m_cache.getArchive(targetId).getCertificates());
-
-        Permissions allPerms = new Permissions();
-        allPerms.add(new AllPermission());
-        m_factory.setSecurityContext(module, new ProtectionDomain(codesource,
-			allPerms));
+        m_factory.setSecurityContext(module, securityContext);
 
         // Create the content loader from the module archive.
         IContentLoader contentLoader = new ContentLoaderImpl(
@@ -3495,7 +3663,8 @@
                 try
                 {
                     BundleInfo info = m_bundle.getInfo();
-                    BundleInfo newInfo = createBundleInfo(info.getArchive());
+                    BundleInfo newInfo = createBundleInfo(info.getArchive(),
+                        info.isExtension());
                     newInfo.syncLock(info);
                     m_bundle.setInfo(newInfo);
                     fireBundleEvent(BundleEvent.UNRESOLVED, m_bundle);
diff --git a/framework/src/main/java/org/apache/felix/framework/SignerMatcher.java b/framework/src/main/java/org/apache/felix/framework/SignerMatcher.java
deleted file mode 100644
index 4a06ffc..0000000
--- a/framework/src/main/java/org/apache/felix/framework/SignerMatcher.java
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * 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.util.*;
-
-import org.osgi.framework.Bundle;
-
-public final class SignerMatcher
-{
-    private BundleImpl m_bundleImpl = null;
-    private String m_filter = null;
-
-    public SignerMatcher(String filter)
-    {
-        m_filter = filter;
-    }
-
-    public SignerMatcher(Bundle bundle)
-    {
-        m_bundleImpl = (BundleImpl) bundle;
-    }
-
-    public boolean equals(Object o)
-    {
-        if (!(o instanceof SignerMatcher))
-        {
-            return false;
-        }
-
-        String pattern = ((SignerMatcher) o).m_filter;
-
-        if (pattern == null)
-        {
-            return true;
-        }
-
-        if (m_bundleImpl == null)
-        {
-            return pattern.trim().equals("\\*");
-        }
-
-        String[] dns = m_bundleImpl.getSubjectDNs();
-
-        if (dns == null)
-        {
-            return pattern.trim().equals("\\*");
-        }
-
-        for (int i = 0;i < dns.length;i++)
-        {
-            if (match(pattern, dns[i]))
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    private static boolean match(String pattern, String dn)
-    {
-        try
-        {
-            return ((pattern != null) && (dn != null)) ?
-                matchDN(pattern.toCharArray(), 0, dn.toCharArray(), 0) : false;
-        }
-        catch (Exception ex)
-        {
-            // TODO: log this or something
-            ex.printStackTrace();
-        }
-
-        return false;
-    }
-
-    private static boolean matchDN(char[] pattern, int pPos, char[] dn, int dPos)
-    {
-        pPos = skip(pattern, pPos, ' ');
-
-        if (pPos >= pattern.length)
-        {
-            return true;
-        }
-
-        int befor = pPos;
-
-        if ((pPos < pattern.length -1) && (pattern[pPos] == '\\') && (pattern[pPos + 1] == '*'))
-        {
-            pPos = pPos + 1;
-        }
-
-        switch (pattern[pPos++])
-        {
-            case '*':
-                pPos = skip(pattern, pPos, ' ');
-                if ((pPos < pattern.length) && (pattern[pPos] == ';'))
-                {
-                    if (matchDN(pattern, ++pPos, dn, dPos))
-                    {
-                        return true;
-                    }
-                    return matchDN(pattern, pPos, dn, skipEscapedUntil(dn, dPos, ';') + 1);
-                }
-                if (pPos >= pattern.length)
-                {
-                    return true;
-                }
-                return matchRDN(pattern, befor, dn, dPos);
-            case '-':
-                pPos = skip(pattern, pPos, ' ');
-                if ((pPos < pattern.length) && (pattern[pPos] == ';'))
-                {
-                    int next = dPos;
-                    pPos++;
-                    do
-                    {
-                        if (matchDN(pattern, pPos, dn, next))
-                        {
-                            return true;
-                        }
-                        next = skipEscapedUntil(dn, next, ';') + 1;
-                    } while (next < dn.length);
-
-                    return false;
-                }
-                if (pPos >= pattern.length)
-                {
-                    return true;
-                }
-                throw new IllegalArgumentException("[" + pPos + "]" + new String(pattern));
-            default:
-                break;
-        }
-
-        return matchRDN(pattern, befor, dn, dPos);
-    }
-
-    private static boolean matchRDN(char[] pattern, int pPos, char[] dn, int dPos)
-    {
-        pPos = skip(pattern, pPos, ' ');
-
-        if (pPos >= pattern.length)
-        {
-            return true;
-        }
-
-        if ((pPos < pattern.length -1) && (pattern[pPos] == '\\') && (pattern[pPos + 1] == '*'))
-        {
-            pPos = pPos + 1;
-        }
-
-        switch (pattern[pPos++])
-        {
-            case '*':
-                pPos = skip(pattern, pPos, ' ');
-                if ((pPos < pattern.length) && (pattern[pPos] == ','))
-                {
-                    pPos++;
-                    do
-                    {
-                        if (matchKV(pattern, pPos, dn, dPos))
-                        {
-                            return true;
-                        }
-
-                        int comma = skipEscapedUntil(dn, dPos, ',');
-                        int colon = skipEscapedUntil(dn, dPos, ';');
-
-                        dPos = (comma > colon) ? colon : comma;
-                    } while ((dPos < dn.length) && (dn[dPos++] == ','));
-                    return false;
-                }
-                throw new IllegalArgumentException("[" + pPos + "]" + new String(pattern));
-            default:
-                break;
-        }
-
-        return matchKV(pattern, pPos - 1, dn, dPos);
-    }
-
-    private static boolean matchKV(char[] pattern, int pPos, char[] dn, int dPos)
-    {
-        pPos = skip(pattern, pPos, ' ');
-
-        if (pPos >= pattern.length)
-        {
-            return false;
-        }
-
-        int equals = skipEscapedUntil(pattern, pPos, '=');
-        int comma = skipEscapedUntil(pattern, pPos, ',');
-        int colon = skipEscapedUntil(pattern, pPos, ';');
-        if (((colon < pattern.length) && (colon < equals)) ||
-            ((comma < pattern.length) && (comma < equals)) ||
-            (equals >= pattern.length))
-        {
-            return false;
-        }
-
-        String key = (String) KEY2OIDSTRING.get(
-            new String(pattern, pPos, equals - pPos).toLowerCase(Locale.US).trim());
-
-        if (key == null)
-        {
-            throw new IllegalArgumentException("Bad key [" +
-                new String(pattern, pPos, equals - pPos) + "] in [" +
-                new String(pattern) + "]");
-        }
-
-        pPos = equals + 1;
-        int keylength = key.length();
-        for (int i = 0;i < keylength;i++)
-        {
-            if ((dPos >= dn.length) || (key.charAt(i) != dn[dPos++]))
-            {
-                return false;
-            }
-        }
-
-        if ((dPos >= dn.length) || (dn[dPos++] != '='))
-        {
-            return false;
-        }
-
-        pPos = skip(pattern, pPos, ' ');
-        if ((pPos < pattern.length -1) && (pattern[pPos] == '\\') && (pattern[pPos + 1] == '*'))
-        {
-            pPos = skip(pattern, pPos + 2, ' ');
-            if (pPos >= pattern.length)
-            {
-                return true;
-            }
-            comma = skipEscapedUntil(dn, dPos, ',');
-            colon = skipEscapedUntil(dn, dPos, ';');
-            if ((pattern[pPos] == ',') && (colon > comma))
-            {
-                return matchKV(pattern, ++pPos, dn, comma + 1);
-            }
-
-            if (pattern[pPos] == ';' )
-            {
-                return matchDN(pattern, ++pPos, dn, colon + 1);
-            }
-
-            return false;
-        }
-        boolean escaped = false;
-        while ((pPos < pattern.length) && (dPos < dn.length))
-        {
-            switch (Character.toLowerCase(pattern[pPos++]))
-            {
-                case ' ':
-                    if ((pattern[pPos - 2] != ' ') && ((dn[dPos++] != ' ') &&
-                        (dn[--dPos] != ';') && (dn[dPos] != ',')))
-                    {
-                        return false;
-                    }
-                    break;
-                case '\\':
-                    escaped = !escaped;
-                    break;
-
-                case '(':
-                case ')':
-                    if (escaped)
-                    {
-                        if (dn[dPos++] != pattern[pPos - 1])
-                        {
-                            return false;
-                        }
-                        escaped = false;
-                        break;
-                    }
-                    return false;
-                case ';':
-                    if (!escaped)
-                    {
-                        if ((dPos < dn.length) && ((dn[dPos] == ',') || (dn[dPos] == ';')))
-                        {
-                            return matchDN(pattern, pPos, dn, skipEscapedUntil(dn, dPos, ';') + 1);
-                        }
-                        return false;
-                    }
-                case ',':
-                    if (!escaped)
-                    {
-                        if ((dPos < dn.length) && (dn[dPos] == ','))
-                        {
-                            return matchKV(pattern, pPos, dn, dPos + 1);
-                        }
-                        return false;
-                    }
-                default:
-                    if (escaped)
-                    {
-                        if (dn[dPos++] != '\\')
-                        {
-                            return false;
-                        }
-                        escaped = false;
-                    }
-                    if (dn[dPos++] != Character.toLowerCase(pattern[pPos - 1]))
-                    {
-                        return false;
-                    }
-                    break;
-            }
-        }
-
-        pPos = skip(pattern, pPos, ' ');
-        if (pPos >= pattern.length)
-        {
-            if ((dPos >= dn.length) || (dn[dPos] == ',') || (dn[dPos] == ';'))
-            {
-                return true;
-            }
-        }
-        else
-        {
-            switch (pattern[pPos++])
-            {
-                case ',':
-                    return matchKV(pattern, pPos, dn, dPos);
-                case ';':
-                    return matchDN(pattern, pPos, dn, dPos);
-                default:
-                    break;
-            }
-        }
-
-        return false;
-    }
-
-    private static final Map KEY2OIDSTRING = new HashMap();
-
-    static {
-        KEY2OIDSTRING.put("2.5.4.3", "cn");
-        KEY2OIDSTRING.put("cn", "cn");
-        KEY2OIDSTRING.put("commonname", "cn");
-        KEY2OIDSTRING.put("2.5.4.4", "sn");
-        KEY2OIDSTRING.put("sn", "sn");
-        KEY2OIDSTRING.put("surname", "sn");
-        KEY2OIDSTRING.put("2.5.4.6", "c");
-        KEY2OIDSTRING.put("c", "c");
-        KEY2OIDSTRING.put("countryname", "c");
-        KEY2OIDSTRING.put("2.5.4.7", "l");
-        KEY2OIDSTRING.put("l", "l");
-        KEY2OIDSTRING.put("localityname", "l");
-        KEY2OIDSTRING.put("2.5.4.8", "st");
-        KEY2OIDSTRING.put("st", "st");
-        KEY2OIDSTRING.put("stateorprovincename", "st");
-        KEY2OIDSTRING.put("2.5.4.10", "o");
-        KEY2OIDSTRING.put("o", "o");
-        KEY2OIDSTRING.put("organizationname", "o");
-        KEY2OIDSTRING.put("2.5.4.11", "ou");
-        KEY2OIDSTRING.put("ou", "ou");
-        KEY2OIDSTRING.put("organizationalunitname", "ou");
-        KEY2OIDSTRING.put("2.5.4.12", "title");
-        KEY2OIDSTRING.put("t", "title");
-        KEY2OIDSTRING.put("title", "title");
-        KEY2OIDSTRING.put("2.5.4.42", "givenname");
-        KEY2OIDSTRING.put("givenname", "givenname");
-        KEY2OIDSTRING.put("2.5.4.43", "initials");
-        KEY2OIDSTRING.put("initials", "initials");
-        KEY2OIDSTRING.put("2.5.4.44", "generationqualifier");
-        KEY2OIDSTRING.put("generationqualifier", "generationqualifier");
-        KEY2OIDSTRING.put("2.5.4.46", "dnqualifier");
-        KEY2OIDSTRING.put("dnqualifier", "dnqualifier");
-        KEY2OIDSTRING.put("2.5.4.9", "street");
-        KEY2OIDSTRING.put("street", "street");
-        KEY2OIDSTRING.put("streetaddress", "street");
-        KEY2OIDSTRING.put("0.9.2342.19200300.100.1.25", "dc");
-        KEY2OIDSTRING.put("dc", "dc");
-        KEY2OIDSTRING.put("domaincomponent", "dc");
-        KEY2OIDSTRING.put("0.9.2342.19200300.100.1.1", "uid");
-        KEY2OIDSTRING.put("uid", "uid");
-        KEY2OIDSTRING.put("userid", "uid");
-        KEY2OIDSTRING.put("1.2.840.113549.1.9.1", "emailaddress");
-        KEY2OIDSTRING.put("emailaddress", "emailaddress");
-        KEY2OIDSTRING.put("2.5.4.5", "serialnumber");
-        KEY2OIDSTRING.put("serialnumber", "serialnumber");
-    }
-
-    private static int skipEscapedUntil(char[] string, int pos, char value)
-    {
-        boolean escaped = false;
-
-        while (pos < string.length)
-        {
-            switch (string[pos++])
-            {
-                case '\\':
-                    escaped = true;
-                    break;
-                default:
-                    if (!escaped)
-                    {
-                        if (string[pos - 1] == value)
-                        {
-                            return pos - 1;
-                        }
-                    }
-                    escaped = false;
-                    break;
-            }
-        }
-
-        return pos;
-    }
-
-    private static int skip(char[] string, int pos, char value)
-    {
-        while (pos < string.length)
-        {
-            if (string[pos] != value)
-            {
-                break;
-            }
-            pos++;
-        }
-
-        return pos;
-    }
-}
diff --git a/framework/src/main/java/org/apache/felix/framework/SystemBundle.java b/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
index a8fc45e..5719640 100644
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
+++ b/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -18,25 +18,32 @@
  */
 package org.apache.felix.framework;
 
+import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.cert.Certificate;
 import java.util.*;
 
-import org.apache.felix.framework.cache.SystemBundleArchive;
-import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.framework.util.StringMap;
-import org.apache.felix.framework.util.manifestparser.Capability;
-import org.apache.felix.framework.util.manifestparser.ManifestParser;
-import org.apache.felix.moduleloader.ICapability;
-import org.apache.felix.moduleloader.IContentLoader;
+import org.apache.felix.framework.cache.*;
+import org.apache.felix.framework.util.*;
+import org.apache.felix.framework.util.manifestparser.*;
+import org.apache.felix.moduleloader.*;
 import org.osgi.framework.*;
 
-class SystemBundle extends BundleImpl
+class SystemBundle extends BundleImpl implements IModuleDefinition, PrivilegedAction
 {
+    private static final Set m_extensionLocations = new HashSet();
+
     private List m_activatorList = null;
-    private BundleActivator m_activator = null;
+    private SystemBundleActivator m_activator = null;
     private Thread m_shutdownThread = null;
     private ICapability[] m_exports = null;
     private IContentLoader m_contentLoader = null;
+    private Set m_exportNames = null;
 
     protected SystemBundle(Felix felix, BundleInfo info, List activatorList)
     {
@@ -54,7 +61,7 @@
         // Add the bundle activator for the start level service.
         activatorList.add(new StartLevelActivator(felix));
 
-        // Add the bundle activator for the URL Handlers service.
+        // Add the bundle activator for the url handler service.
         activatorList.add(new URLHandlersActivator(felix));
 
         m_activatorList = activatorList;
@@ -67,7 +74,7 @@
         // packages should be exported by the system bundle.
         try
         {
-            m_exports = (ICapability[]) ManifestParser.parseExportHeader(
+            m_exports = ManifestParser.parseExportHeader(
                 getFelix().getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES));
         }
         catch (Exception ex)
@@ -79,9 +86,29 @@
                 + getFelix().getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES), ex);
         }
 
-        m_contentLoader = new SystemBundleContentLoader(getFelix().getLogger());
+        m_contentLoader = new SystemBundleContentLoader();
 
+        // Initialize header map as a case insensitive map.
+        Map map = new StringMap(false);
+        map.put(FelixConstants.BUNDLE_VERSION,
+            getFelix().getConfig().get(FelixConstants.FELIX_VERSION_PROPERTY));
+        map.put(FelixConstants.BUNDLE_SYMBOLICNAME,
+            FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME);
+        map.put(FelixConstants.BUNDLE_NAME, "System Bundle");
+        map.put(FelixConstants.BUNDLE_DESCRIPTION,
+            "This bundle is system specific; it implements various system services.");
+        map.put(FelixConstants.EXPORT_SERVICE, "org.osgi.service.packageadmin.PackageAdmin,org.osgi.service.startlevel.StartLevel");
+
+        parseAndAddExports(map);
+
+        ((SystemBundleArchive) getInfo().getArchive()).setManifestHeader(map);
+    }
+
+    private void parseAndAddExports(Map headers)
+    {
         StringBuffer exportSB = new StringBuffer("");
+        Set exportNames = new HashSet();
+
         for (int i = 0; i < m_exports.length; i++)
         {
             if (i > 0)
@@ -93,24 +120,13 @@
             exportSB.append("; version=\"");
             exportSB.append(((Capability) m_exports[i]).getPackageVersion().toString());
             exportSB.append("\"");
+
+            exportNames.add(((Capability) m_exports[i]).getPackageName());
         }
 
-        // Initialize header map as a case insensitive map.
-        Map map = new StringMap(false);
-        map.put(FelixConstants.BUNDLE_VERSION,
-            getFelix().getConfig().get(FelixConstants.FELIX_VERSION_PROPERTY));
-        map.put(FelixConstants.BUNDLE_SYMBOLICNAME,
-            FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME);
-        map.put(FelixConstants.BUNDLE_NAME, "System Bundle");
-        map.put(FelixConstants.BUNDLE_DESCRIPTION,
-            "This bundle is system specific; it implements various system services.");
-        map.put(FelixConstants.EXPORT_PACKAGE, exportSB.toString());
-        map.put(FelixConstants.EXPORT_SERVICE, "org.osgi.service.packageadmin.PackageAdmin,org.osgi.service.startlevel.StartLevel");
-        ((SystemBundleArchive) getInfo().getArchive()).setManifestHeader(map);
+        m_exportNames = exportNames;
 
-        // TODO: FRAMEWORK - We need some systematic way for framework services
-        // to add packages and services to the system bundle's headers, something
-        // that will allow for them to be independently configured.
+        headers.put(FelixConstants.EXPORT_PACKAGE, exportSB.toString());
     }
 
     public ICapability[] getExports()
@@ -123,7 +139,7 @@
         return m_contentLoader;
     }
 
-    public synchronized void start() throws BundleException
+    public void start() throws BundleException
     {
         // The system bundle is only started once and it
         // is started by the framework.
@@ -156,7 +172,7 @@
      * multiple calls to this method, the shutdown thread is only started if
      * the framework is still in running state.
      */
-    public synchronized void stop()
+    public void stop()
     {
         Object sm = System.getSecurityManager();
 
@@ -191,17 +207,17 @@
         }
     }
 
-    public synchronized void uninstall() throws BundleException
+    public void uninstall() throws BundleException
     {
         throw new BundleException("Cannot uninstall the system bundle.");
     }
 
-    public synchronized void update() throws BundleException
+    public void update() throws BundleException
     {
         update(null);
     }
 
-    public synchronized void update(InputStream is) throws BundleException
+    public void update(InputStream is) throws BundleException
     {
         Object sm = System.getSecurityManager();
 
@@ -223,13 +239,13 @@
         }
         return m_activator;
     }
-    
+
     /**
      * Actually shuts down the system bundle. This method does what actually
      * the {@link #stop()} method would do for regular bundles. Since the system
      * bundle has to shutdown the framework, a separate method is used to stop
      * the system bundle during framework shutdown.
-     * 
+     *
      * @throws BundleException If an error occurrs stopping the system bundle
      *      and any activators "started" on framework start time.
      */
@@ -238,11 +254,266 @@
         // Callback from shutdown thread, so do our own stop.
         try
         {
-            getActivator().stop(getInfo().getContext());
+            getFelix().m_secureAction.stopActivator(getActivator(),
+                getInfo().getContext());
         }
         catch (Throwable throwable)
         {
             throw new BundleException( "Unable to stop system bundle.", throwable );
         }
     }
+
+    boolean exports(String packageName)
+    {
+        return m_exportNames.contains(packageName);
+    }
+
+    public ICapability[] getCapabilities()
+    {
+        return m_exports;
+    }
+
+    public IRequirement[] getDynamicRequirements()
+    {
+        return null;
+    }
+
+    public R4Library[] getLibraries()
+    {
+        return null;
+    }
+
+    public IRequirement[] getRequirements()
+    {
+        return null;
+    }
+
+    private final ThreadLocal m_tempBundle = new ThreadLocal();
+
+    void addExtensionBundle(BundleImpl bundle)
+    {
+        if (System.getSecurityManager() != null)
+        {
+            m_tempBundle.set(bundle);
+
+            try
+            {
+                AccessController.doPrivileged(this);
+            }
+            finally
+            {
+                m_tempBundle.set(null);
+            }
+        }
+        else
+        {
+            _addExtensionBundle(bundle);
+        }
+    }
+
+    public Object run()
+    {
+        _addExtensionBundle((BundleImpl) m_tempBundle.get());
+        return null;
+    }
+
+    private void _addExtensionBundle(BundleImpl bundle)
+    {
+        BundleArchive archive = bundle.getInfo().getArchive();
+
+        SystemBundleArchive systemArchive =
+            (SystemBundleArchive) getInfo().getArchive();
+
+        Map headers;
+        ICapability[] exports;
+        try
+        {
+            headers = new StringMap(systemArchive.getManifestHeader(
+                systemArchive.getRevisionCount() - 1), false);
+
+            exports = ManifestParser.parseExportHeader((String)
+                bundle.getInfo().getCurrentHeader().get(Constants.EXPORT_PACKAGE));
+        }
+        catch (Exception ex)
+        {
+            getFelix().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error parsing extension bundle export statement: "
+                + bundle.getInfo().getCurrentHeader().get(Constants.EXPORT_PACKAGE), ex);
+
+            return;
+        }
+
+        try
+        {
+            String url = archive.getRevision(
+                archive.getRevisionCount() -1).getCachedBundleURL();
+            if (url != null)
+            {
+                synchronized (getClass().getClassLoader())
+                {
+                    if (!m_extensionLocations.contains(bundle.getSymbolicName()))
+                    {
+                        Method addURL =
+                            URLClassLoader.class.getDeclaredMethod("addURL",
+                            new Class[] {URL.class});
+                        addURL.setAccessible(true);
+                        addURL.invoke(getClass().getClassLoader(),
+                            new Object[] {new URL(url)});
+                        m_extensionLocations.add(bundle.getSymbolicName());
+                    }
+                }
+            }
+            else
+            {
+                getFelix().getLogger().log(Logger.LOG_WARNING,
+                    "Unable to add extension bundle to FrameworkClassLoader - Maybe BundleCache does not support URLs?");
+                throw new UnsupportedOperationException(
+                    "Unable to add extension bundle to FrameworkClassLoader - Maybe BundleCache does not support URLs?");
+            }
+        }
+        catch (UnsupportedOperationException ex)
+        {
+            throw ex;
+        }
+        catch (Exception ex)
+        {
+            getFelix().getLogger().log(Logger.LOG_WARNING,
+                "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?", ex);
+            throw new UnsupportedOperationException(
+                "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?");
+        }
+
+                ICapability[] temp = new ICapability[m_exports.length + exports.length];
+
+        System.arraycopy(m_exports, 0, temp, 0, m_exports.length);
+        System.arraycopy(exports, 0, temp, m_exports.length, exports.length);
+
+        m_exports = temp;
+
+        parseAndAddExports(headers);
+
+        systemArchive.setManifestHeader(headers);
+
+        String activatorClass = (String)
+            bundle.getInfo().getCurrentHeader().get(
+            FelixConstants.FELIX_EXTENSION_ACTIVATOR);
+
+        if (activatorClass != null)
+        {
+            try
+            {
+                m_activator.addActivator(((BundleActivator)
+                    getClass().getClassLoader().loadClass(
+                    activatorClass.trim()).newInstance()),
+                    new BundleContextImpl(getFelix(), bundle));
+            }
+            catch (Throwable ex)
+            {
+                getFelix().getLogger().log(Logger.LOG_WARNING,
+                    "Unable to start Felix Extension Activator", ex);
+            }
+        }
+    }
+
+    private class SystemBundleContentLoader implements IContentLoader
+    {
+        private ISearchPolicy m_searchPolicy = null;
+        private IURLPolicy m_urlPolicy = null;
+
+        public void open()
+        {
+            // Nothing needed here.
+        }
+
+        public void close()
+        {
+            // Nothing needed here.
+        }
+
+        public IContent getContent()
+        {
+            return null;
+        }
+
+        public ISearchPolicy getSearchPolicy()
+        {
+            return m_searchPolicy;
+        }
+
+        public void setSearchPolicy(ISearchPolicy searchPolicy)
+        {
+            m_searchPolicy = searchPolicy;
+        }
+
+        public IURLPolicy getURLPolicy()
+        {
+            return m_urlPolicy;
+        }
+
+        public void setURLPolicy(IURLPolicy urlPolicy)
+        {
+            m_urlPolicy = urlPolicy;
+        }
+
+        public Class getClass(String name)
+        {
+            if (!m_exportNames.contains(Util.getClassPackage(name)))
+            {
+                return null;
+            }
+
+            try
+            {
+                return getClass().getClassLoader().loadClass(name);
+            }
+            catch (ClassNotFoundException ex)
+            {
+                getFelix().getLogger().log(
+                    Logger.LOG_WARNING,
+                    ex.getMessage(),
+                    ex);
+            }
+            return null;
+        }
+
+        public URL getResource(String name)
+        {
+            return getClass().getClassLoader().getResource(name);
+        }
+
+        public Enumeration getResources(String name)
+        {
+           try
+           {
+               return getClass().getClassLoader().getResources(name);
+           }
+           catch (IOException ex)
+           {
+               return null;
+           }
+        }
+
+        public URL getResourceFromContent(String name)
+        {
+            // There is no content for the system bundle, so return null.
+            return null;
+        }
+
+        public boolean hasInputStream(String urlPath) throws IOException
+        {
+            return (getClass().getClassLoader().getResource(urlPath) != null);
+        }
+
+        public InputStream getInputStream(String urlPath) throws IOException
+        {
+            return getClass().getClassLoader().getResourceAsStream(urlPath);
+        }
+
+        public String findLibrary(String name)
+        {
+            // No native libs associated with the system bundle.
+            return null;
+        }
+    }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java b/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java
index 68e333f..94d74ed 100644
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java
+++ b/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -18,7 +18,7 @@
  */
 package org.apache.felix.framework;
 
-import java.util.List;
+import java.util.*;
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -28,6 +28,7 @@
     private Felix m_felix = null;
     private List m_activatorList = null;
     private BundleContext m_context = null;
+    private Map m_activatorContextMap = null;
 
     SystemBundleActivator(Felix felix, List activatorList)
     {
@@ -56,7 +57,17 @@
             // Stop all activators.
             for (int i = 0; i < m_activatorList.size(); i++)
             {
-                ((BundleActivator) m_activatorList.get(i)).stop(context);
+                if ((m_activatorContextMap != null) &&
+                    m_activatorContextMap.containsKey(m_activatorList.get(i)))
+                {
+                    ((BundleActivator) m_activatorList.get(i)).stop(
+                        (BundleContext) m_activatorContextMap.get(
+                        m_activatorList.get(i)));
+                }
+                else
+                {
+                    ((BundleActivator) m_activatorList.get(i)).stop(context);
+                }
             }
         }
     }
@@ -65,4 +76,30 @@
     {
         return m_context;
     }
+
+    void addActivator(BundleActivator activator, BundleContext context) throws Exception
+    {
+        if (m_activatorList == null)
+        {
+            m_activatorList = new ArrayList();
+        }
+
+        m_activatorList.add(activator);
+
+        if (context != null)
+        {
+            if (m_activatorContextMap == null)
+            {
+                m_activatorContextMap = new HashMap();
+            }
+
+            m_activatorContextMap.put(activator, context);
+
+            activator.start(context);
+        }
+        else if (m_context != null)
+        {
+            activator.start(m_context);
+        }
+    }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java b/framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java
deleted file mode 100644
index 6fc10df..0000000
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
-
-import org.apache.felix.moduleloader.*;
-
-public class SystemBundleContentLoader implements IContentLoader
-{
-    private Logger m_logger = null;
-    private ISearchPolicy m_searchPolicy = null;
-    private IURLPolicy m_urlPolicy = null;
-
-    public SystemBundleContentLoader(Logger logger)
-    {
-        m_logger = logger;
-    }
-
-    public void open()
-    {
-        // Nothing needed here.
-    }
-
-    public void close()
-    {
-        // Nothing needed here.
-    }
-
-    public IContent getContent()
-    {
-        return null;
-    }
-
-    public ISearchPolicy getSearchPolicy()
-    {
-        return m_searchPolicy;
-    }
-
-    public void setSearchPolicy(ISearchPolicy searchPolicy)
-    {
-        m_searchPolicy = searchPolicy;
-    }
-
-    public IURLPolicy getURLPolicy()
-    {
-        return m_urlPolicy;
-    }
-
-    public void setURLPolicy(IURLPolicy urlPolicy)
-    {
-        m_urlPolicy = urlPolicy;
-    }
-
-    public Class getClass(String name)
-    {
-        try
-        {
-            return getClass().getClassLoader().loadClass(name);
-        }
-        catch (ClassNotFoundException ex)
-        {
-            m_logger.log(
-                Logger.LOG_WARNING,
-                ex.getMessage(),
-                ex);
-        }
-        return null;
-    }
-
-    public URL getResource(String name)
-    {
-        return getClass().getClassLoader().getResource(name);
-    }
-
-    public Enumeration getResources(String name)
-    {
-       try
-       {
-           return getClass().getClassLoader().getResources(name);
-       }
-       catch (IOException ex)
-       {
-           return null;
-       }
-    }
-
-    public URL getResourceFromContent(String name)
-    {
-        // There is no content for the system bundle, so return null.
-        return null;
-    }
-
-    public boolean hasInputStream(String urlPath) throws IOException
-    {
-        return (getClass().getClassLoader().getResource(urlPath) != null);
-    }
-
-    public InputStream getInputStream(String urlPath) throws IOException
-    {
-        return getClass().getClassLoader().getResourceAsStream(urlPath);
-    }
-
-    public String findLibrary(String name)
-    {
-        // No native libs associated with the system bundle.
-        return null;
-    }
-}
\ No newline at end of file