You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2007/02/13 00:49:44 UTC

svn commit: r506754 - /incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/

Author: pauls
Date: Mon Feb 12 15:49:43 2007
New Revision: 506754

URL: http://svn.apache.org/viewvc?view=rev&rev=506754
Log:
Implement the extension:=framework part of extension bundles minus the automatic framework restart (FELIX-30). 

Removed:
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SignerMatcher.java
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleContentLoader.java
Modified:
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
    incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java

Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java?view=diff&rev=506754&r1=506753&r2=506754
==============================================================================
--- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java (original)
+++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java Mon Feb 12 15:49:43 2007
@@ -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.");
     }
 }

Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java?view=diff&rev=506754&r1=506753&r2=506754
==============================================================================
--- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java (original)
+++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java Mon Feb 12 15:49:43 2007
@@ -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;
     }
 }

Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java?view=diff&rev=506754&r1=506753&r2=506754
==============================================================================
--- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java (original)
+++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java Mon Feb 12 15:49:43 2007
@@ -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;
@@ -473,6 +478,16 @@
     public void setStale()
     {
         m_stale = true;
+    }
+
+    public boolean isExtension()
+    {
+        return m_extension;
+    }
+
+    public void setExtension(boolean extension)
+    {
+        m_extension = extension;
     }
 
     //

Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?view=diff&rev=506754&r1=506753&r2=506754
==============================================================================
--- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Mon Feb 12 15:49:43 2007
@@ -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())
+                {
+                    Object sm = System.getSecurityManager();
+                    if (sm != null)
+                    {
+                        ((SecurityManager) sm).checkPermission(
+                            new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+                    }
+                }
+                else
                 {
-                    ((SecurityManager) sm).checkPermission(
-                        new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+                    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);

Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java?view=diff&rev=506754&r1=506753&r2=506754
==============================================================================
--- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java (original)
+++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java Mon Feb 12 15:49:43 2007
@@ -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;
         }
     }
 }

Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java?view=diff&rev=506754&r1=506753&r2=506754
==============================================================================
--- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java (original)
+++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java Mon Feb 12 15:49:43 2007
@@ -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);
+                }
             }
         }
     }
@@ -64,5 +75,31 @@
     public BundleContext getBundleContext()
     {
         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);
+        }
     }
 }