Clean-up the extension bundle implementation and cater for more then one felix instance (FELIX-30).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@549283 13f79535-47bb-0310-9956-ffa450edef68
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 223813c..6b46608 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -35,6 +35,9 @@
 
 public class Felix
 {
+    // The secure action used to do privileged calls
+    static SecureAction m_secureAction = new SecureAction();
+    
     // Logging related member variables.
     private Logger m_logger = null;
     // Config properties.
@@ -103,9 +106,6 @@
     private String m_executionEnvironment = "";
     private Set m_executionEnvironmentCache = new HashSet();
 
-    // The secure action used to do privileged calls
-    protected SecureAction m_secureAction = new SecureAction();
-
     /**
      * <p>
      * This method starts the framework instance; instances of the framework
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 529022a..57b2d25 100644
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
+++ b/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
@@ -20,11 +20,9 @@
 
 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.net.URLConnection;
+import java.net.URLStreamHandler;
 import java.util.*;
 
 import org.apache.felix.framework.cache.*;
@@ -33,8 +31,27 @@
 import org.apache.felix.moduleloader.*;
 import org.osgi.framework.*;
 
-class SystemBundle extends BundleImpl implements IModuleDefinition, PrivilegedAction
+class SystemBundle extends BundleImpl implements IModuleDefinition
 {
+    private static final ExtensionManager m_extensionManager;
+
+    static 
+    {
+        ExtensionManager extensionManager = new ExtensionManager();
+        try 
+        {
+            Felix.m_secureAction.addURLToURLClassLoader(Felix.m_secureAction.createURL(
+                Felix.m_secureAction.createURL(null, "felix:", extensionManager),
+                "felix://extensions/", extensionManager), 
+                SystemBundle.class.getClassLoader());
+        } 
+        catch (Exception ex) 
+        {
+            extensionManager = null;
+        }
+        m_extensionManager = extensionManager;
+    }
+    
     private List m_activatorList = null;
     private Map m_activatorContextMap = null;
     private IContentLoader m_contentLoader = null;
@@ -147,7 +164,7 @@
         try
         {
             getInfo().setBundleContext(new BundleContextImpl(getFelix(), this));
-            getInfo().getActivator().start(getInfo().getBundleContext());
+            Felix.m_secureAction.startActivator(getInfo().getActivator(), getInfo().getBundleContext());
         }
         catch (Throwable throwable)
         {
@@ -209,37 +226,8 @@
         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)
-    {
         SystemBundleArchive systemArchive =
             (SystemBundleArchive) getInfo().getArchive();
 
@@ -263,19 +251,13 @@
             return;
         }
 
-        try
+        if (m_extensionManager != null) 
         {
-            Method addURL =
-                URLClassLoader.class.getDeclaredMethod("addURL",
-                new Class[] {URL.class});
-            addURL.setAccessible(true);
-            addURL.invoke(getClass().getClassLoader(),
-                new Object[] {bundle.getEntry("/")});
+            m_extensionManager.addExtension(getFelix(), bundle);
         }
-        catch (Exception ex)
-        {
+        else {
             getFelix().getLogger().log(Logger.LOG_WARNING,
-                "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?", ex);
+                "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?");
             throw new UnsupportedOperationException(
                 "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?");
         }
@@ -312,7 +294,7 @@
                 }
                 BundleContext context = new BundleContextImpl(getFelix(), bundle);
                 m_activatorContextMap.put(activator, context);
-                activator.start(context);
+                Felix.m_secureAction.startActivator(activator, context);
             }
             catch (Throwable ex)
             {
@@ -331,7 +313,8 @@
             // Start all activators.
             for (int i = 0; i < m_activatorList.size(); i++)
             {
-                ((BundleActivator) m_activatorList.get(i)).start(context);
+                Felix.m_secureAction.startActivator(
+                    (BundleActivator) m_activatorList.get(i), context);
             }
         }
 
@@ -375,13 +358,13 @@
                         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)));
+                            Felix.m_secureAction.stopActivator((BundleActivator) m_activatorList.get(i),
+                                (BundleContext) m_activatorContextMap.get(m_activatorList.get(i)));
                         }
                         else
                         {
-                            ((BundleActivator) m_activatorList.get(i)).stop(getInfo().getBundleContext());
+                            Felix.m_secureAction.stopActivator((BundleActivator) m_activatorList.get(i),
+                                getInfo().getBundleContext());
                         }
                     }
                     catch (Throwable throwable)
@@ -393,6 +376,11 @@
                     }
                 }
             }
+             
+            if (m_extensionManager != null)
+            {
+                m_extensionManager.removeExtensions(getFelix());
+            }
 
             // Lastly, complete the shutdown.
             try
@@ -508,4 +496,74 @@
             return null;
         }
     }
+
+    private static class ExtensionManager extends URLStreamHandler 
+    {
+        private final List m_extensions = new ArrayList();
+        private final Set m_names = new HashSet();
+        private final Map m_sourceToExtensions = new HashMap();
+
+        protected synchronized URLConnection openConnection(URL url) throws IOException
+        {
+            String path = url.getPath();
+
+            if (path.trim().equals("/"))
+            {
+                throw new IOException("Resource not provided by any extension!");
+            }
+
+            for (Iterator iter = m_extensions.iterator(); iter.hasNext();)
+            {
+                URL result = ((Bundle) iter.next()).getEntry(path);
+
+                if (result != null)
+                {
+                    return result.openConnection();
+                }
+            }
+
+            throw new IOException("Resource not provided by any extension!");
+        }
+        
+        synchronized void addExtension(Object source, Bundle extension)
+        {
+            List sourceExtensions = (List) m_sourceToExtensions.get(source);
+
+            if (sourceExtensions == null)
+            {
+                sourceExtensions = new ArrayList();
+                m_sourceToExtensions.put(source, sourceExtensions);
+            }
+
+            sourceExtensions.add(extension);
+
+            _add(extension.getSymbolicName(), extension);
+        }
+
+        synchronized void removeExtensions(Object source)
+        {
+            if (m_sourceToExtensions.remove(source) == null)
+            {
+                return;
+            }
+
+            m_extensions.clear();
+            m_names.clear();
+
+            for (Iterator iter = m_sourceToExtensions.values().iterator(); iter.hasNext();)
+            {
+                Bundle bundle = (Bundle) iter.next();
+                _add(bundle.getSymbolicName(), bundle);
+            }
+        }
+
+        private void _add(String name, Bundle extension)
+        {
+            if (!m_names.contains(name))
+            {
+                m_names.add(name);
+                m_extensions.add(extension);
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
index 909b069..745018d 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
@@ -19,6 +19,7 @@
 package org.apache.felix.framework.util;
 
 import java.io.*;
+import java.lang.reflect.Method;
 import java.net.*;
 import java.security.*;
 import java.util.jar.JarFile;
@@ -654,6 +655,32 @@
         }
     }
 
+    public void addURLToURLClassLoader(URL extension, ClassLoader loader) throws Exception 
+    {
+        if (System.getSecurityManager() != null) 
+        {
+            Actions actions = (Actions) m_actions.get();
+            actions.set(Actions.ADD_EXTENSION_URL, extension, loader);
+            try 
+            {
+                AccessController.doPrivileged(actions, m_acc);
+            } 
+            catch (PrivilegedActionException e) 
+            {
+                throw e.getException();
+            }
+        }
+        else 
+        {
+            Method addURL =
+                URLClassLoader.class.getDeclaredMethod("addURL",
+                new Class[] {URL.class});
+            addURL.setAccessible(true);
+            addURL.invoke(getClass().getClassLoader(), 
+                new Object[]{extension, loader});
+        }
+    }
+    
     private static class Actions implements PrivilegedExceptionAction
     {
         public static final int GET_PROPERTY_ACTION = 0;
@@ -681,7 +708,7 @@
         public static final int CREATE_TMPFILE_ACTION = 22;
         public static final int OPEN_URLCONNECTION_ACTION = 23;
         public static final int OPEN_JARURLCONNECTIONJAR_ACTION = 24;
-
+        public static final int ADD_EXTENSION_URL = 25;
 
         private int m_action = -1;
         private Object m_arg1 = null;
@@ -853,6 +880,14 @@
                 {
                     return ((JarURLConnection) m_arg1).getJarFile();
                 }
+                else if (m_action == ADD_EXTENSION_URL) 
+                {
+                    Method addURL =
+                        URLClassLoader.class.getDeclaredMethod("addURL",
+                        new Class[] {URL.class});
+                    addURL.setAccessible(true);
+                    addURL.invoke(m_arg2, new Object[]{m_arg1});
+                }
 
                 return null;
             }