You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2007/05/31 22:07:12 UTC

svn commit: r543242 - in /felix/trunk/framework/src/main/java/org/apache/felix/framework: BundleImpl.java BundleInfo.java Felix.java SystemBundle.java SystemBundleActivator.java URLHandlersContentHandlerProxy.java URLHandlersStreamHandlerProxy.java

Author: rickhall
Date: Thu May 31 13:07:11 2007
New Revision: 543242

URL: http://svn.apache.org/viewvc?view=rev&rev=543242
Log:
Tried to improve Felix' shutdown sequence, which was confusing and perhaps
not altogether correct. Now all shutdowns occur via calling stop() on the
system bundle and Felix stops the system bundle now in a similar fashion
as normal bundles to ensure that proper events are fired.

Removed:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleActivator.java
Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java?view=diff&rev=543242&r1=543241&r2=543242
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java Thu May 31 13:07:11 2007
@@ -54,7 +54,7 @@
 
     public BundleContext getBundleContext()
     {
-        return m_info.getContext();
+        return m_info.getBundleContext();
     }
 
     public long getBundleId()

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java?view=diff&rev=543242&r1=543241&r2=543242
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java Thu May 31 13:07:11 2007
@@ -450,12 +450,12 @@
         }
     }
 
-    public BundleContext getContext()
+    public BundleContext getBundleContext()
     {
         return m_context;
     }
 
-    public void setContext(BundleContext context)
+    public void setBundleContext(BundleContext context)
     {
         m_context = context;
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?view=diff&rev=543242&r1=543241&r2=543242
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Thu May 31 13:07:11 2007
@@ -395,7 +395,7 @@
 
         // Now that the system bundle is successfully created we can give
         // its bundle context to the logger so that it can track log services.
-        m_logger.setSystemBundleContext(systembundle.getInfo().getContext());
+        m_logger.setSystemBundleContext(systembundle.getInfo().getBundleContext());
 
         // Now reload the cached bundles.
         BundleArchive[] archives = null;
@@ -523,36 +523,41 @@
      * This method cleanly shuts down the framework, it must be called at the
      * end of a session in order to shutdown all active bundles.
     **/
-    public synchronized void shutdown()
+    public void shutdown()
     {
-        // Change framework status from running to stopping.
-        // If framework is not running, then just return.
-        if (m_frameworkStatus != RUNNING_STATUS)
+        // Shut the framework down by calling stop() on the system bundle.
+        // Since stop() on the system bundle will return immediately, we
+        // will synchronize on the framework instance so we can use it to
+        // be notified when the shutdown is complete.
+        synchronized (this)
         {
-            return;
-        }
-
-        // The framework is now in its shutdown sequence.
-        m_frameworkStatus = STOPPING_STATUS;
-
-        // Do the real shutdown work in a separate method to catch any problems
-        // without requiring a huge and ugly try-catch statement.
-        try
-        {
-            shutdownInternal();
-        }
-        catch (Exception ex)
-        {
-            fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
-            m_logger.log(Logger.LOG_ERROR, "Error stopping framework.", ex);
-        }
+            if (m_frameworkStatus == RUNNING_STATUS)
+            {
+                try
+                {
+                    getBundle(0).stop();
+                }
+                catch (BundleException ex)
+                {
+                    fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
+                    m_logger.log(
+                        Logger.LOG_ERROR,
+                        "Error stopping system bundle.",
+                        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");
-        if (!isEmbedded)
-        {
-            m_secureAction.exit(0);
+            while (m_frameworkStatus != INITIAL_STATUS)
+            {
+                try
+                {
+                    wait();
+                }
+                catch (InterruptedException ex)
+                {
+                    // Keep waiting if necessary.
+                }
+            }
         }
     }
 
@@ -562,8 +567,21 @@
      * the system bundle, cleaning up any bundle remains and shutting down event
      * dispatching.
      */
-    private void shutdownInternal()
+    void shutdownInternal()
     {
+        synchronized (this)
+        {
+            // Change framework status from running to stopping.
+            // If framework is not running, then just return.
+            if (m_frameworkStatus != RUNNING_STATUS)
+            {
+                return;
+            }
+
+            // The framework is now in its shutdown sequence.
+            m_frameworkStatus = STOPPING_STATUS;
+        }
+
         // Use the start level service to set the start level to zero
         // in order to stop all bundles in the framework. Since framework
         // shutdown happens on its own thread, we can wait for the start
@@ -581,22 +599,6 @@
             // Should never happen.
         }
 
-        // Just like initialize() called the system bundle's start()
-        // method, we must call its stop() method here so that it
-        // can perform any necessary clean up.
-        // Actually, the stop() method just asynchronously would call
-        // this method through shutdown(), hence we call the real SystemBundle
-        // shutdown method.
-        try
-        {
-            ((SystemBundle) getBundle(0)).shutdown();
-        }
-        catch (Exception ex)
-        {
-            fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
-            m_logger.log(Logger.LOG_ERROR, "Error stopping system bundle.", ex);
-        }
-
         // Since they may be updated and uninstalled bundles that
         // have not been refreshed, we will take care of refreshing
         // them during shutdown.
@@ -643,29 +645,41 @@
         // Shutdown event dispatching queue.
         EventDispatcher.shutdown();
 
-        // The framework is no longer in a usable state.
-        m_frameworkStatus = INITIAL_STATUS;
-
         // Remove all bundles from the module factory so that any
         // open resources will be closed.
         bundles = getBundles();
         for (int i = 0; i < bundles.length; i++)
         {
             BundleImpl bundle = (BundleImpl) bundles[i];
-            try
+            IModule[] modules = bundle.getInfo().getModules();
+            for (int j = 0; j < modules.length; j++)
             {
-                IModule[] modules = bundle.getInfo().getModules();
-                for (int j = 0; j < modules.length; j++)
+                try
                 {
                     m_factory.removeModule(modules[j]);
                 }
-            }
-            catch (Exception ex)
-            {
-                m_logger.log(Logger.LOG_ERROR,
-                   "Unable to clean up " + bundle.getInfo().getLocation(), ex);
+                catch (Exception ex)
+                {
+                    m_logger.log(Logger.LOG_ERROR,
+                       "Unable to clean up " + bundle.getInfo().getLocation(), ex);
+                }
             }
         }
+
+        // Notify any waiters that the framework is back in its initial state.
+        synchronized (this)
+        {
+            m_frameworkStatus = INITIAL_STATUS;
+            notifyAll();
+        }
+
+        // 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");
+        if (!isEmbedded)
+        {
+            m_secureAction.exit(0);
+        }
     }
 
     public int getStatus()
@@ -1281,7 +1295,7 @@
         try
         {
             // Set the bundle's context.
-            info.setContext(new BundleContextImpl(this, bundle));
+            info.setBundleContext(new BundleContextImpl(this, bundle));
 
             // Set the bundle's activator.
             info.setActivator(createBundleActivator(bundle.getInfo()));
@@ -1289,8 +1303,7 @@
             // Activate the bundle if it has an activator.
             if (bundle.getInfo().getActivator() != null)
             {
-                m_secureAction.startActivator(info.getActivator(),
-                    info.getContext());
+                m_secureAction.startActivator(info.getActivator(),info.getBundleContext());
             }
 
             // TODO: CONCURRENCY - Reconsider firing event outside of the
@@ -1305,8 +1318,8 @@
             info.setState(Bundle.RESOLVED);
 
             // Clean up the bundle context.
-            ((BundleContextImpl) info.getContext()).invalidate();
-            info.setContext(null);
+            ((BundleContextImpl) info.getBundleContext()).invalidate();
+            info.setBundleContext(null);
 
             // Unregister any services offered by this bundle.
             m_registry.unregisterServices(bundle);
@@ -1667,8 +1680,7 @@
         {
             if (bundle.getInfo().getActivator() != null)
             {
-                m_secureAction.stopActivator(info.getActivator(),
-                    info.getContext());
+                m_secureAction.stopActivator(info.getActivator(),info.getBundleContext());
             }
 
             // Try to save the activator in the cache.
@@ -1696,22 +1708,27 @@
             rethrow = th;
         }
 
-        // Clean up the bundle context.
-        ((BundleContextImpl) info.getContext()).invalidate();
-        info.setContext(null);
-
-        // Unregister any services offered by this bundle.
-        m_registry.unregisterServices(bundle);
-
-        // Release any services being used by this bundle.
-        m_registry.ungetServices(bundle);
-
-        // The spec says that we must remove all event
-        // listeners for a bundle when it is stopped.
-        m_dispatcher.removeListeners(bundle);
+        // Do not clean up after the system bundle since it will
+        // clean up after itself.
+        if (info.getBundleId() != 0)
+        {
+            // Clean up the bundle context.
+            ((BundleContextImpl) info.getBundleContext()).invalidate();
+            info.setBundleContext(null);
 
-        info.setState(Bundle.RESOLVED);
-        fireBundleEvent(BundleEvent.STOPPED, bundle);
+            // Unregister any services offered by this bundle.
+            m_registry.unregisterServices(bundle);
+
+            // Release any services being used by this bundle.
+            m_registry.ungetServices(bundle);
+
+            // The spec says that we must remove all event
+            // listeners for a bundle when it is stopped.
+            m_dispatcher.removeListeners(bundle);
+
+            info.setState(Bundle.RESOLVED);
+            fireBundleEvent(BundleEvent.STOPPED, bundle);
+        }
 
         // Throw activator error if there was one.
         if (rethrow != null)

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java?view=diff&rev=543242&r1=543241&r2=543242
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundle.java Thu May 31 13:07:11 2007
@@ -36,11 +36,11 @@
 class SystemBundle extends BundleImpl implements IModuleDefinition, PrivilegedAction
 {
     private List m_activatorList = null;
-    private SystemBundleActivator m_activator = null;
-    private Thread m_shutdownThread = null;
-    private ICapability[] m_exports = null;
+    private Map m_activatorContextMap = null;
     private IContentLoader m_contentLoader = null;
+    private ICapability[] m_exports = null;
     private Set m_exportNames = null;
+    private Thread m_shutdownThread = null;
 
     protected SystemBundle(Felix felix, BundleInfo info, List activatorList)
     {
@@ -63,6 +63,8 @@
 
         m_activatorList = activatorList;
 
+        info.setActivator(new SystemBundleActivator());
+        
         // The system bundle exports framework packages as well as
         // arbitrary user-defined packages from the system class path.
         // We must construct the system bundle's export metadata.
@@ -149,8 +151,8 @@
 
         try
         {
-            getInfo().setContext(new BundleContextImpl(getFelix(), this));
-            getActivator().start(getInfo().getContext());
+            getInfo().setBundleContext(new BundleContextImpl(getFelix(), this));
+            getInfo().getActivator().start(getInfo().getBundleContext());
         }
         catch (Throwable throwable)
         {
@@ -163,45 +165,9 @@
         // This will be done after the framework is initialized.
     }
 
-    /**
-     * According to the spec, this method asynchronously stops the framework.
-     * To prevent multiple creations of useless separate threads in case of
-     * multiple calls to this method, the shutdown thread is only started if
-     * the framework is still in running state.
-     */
-    public void stop()
+    public void stop() throws BundleException
     {
-        Object sm = System.getSecurityManager();
-
-        if (sm != null)
-        {
-            ((SecurityManager) sm).checkPermission(new AdminPermission(this,
-                AdminPermission.EXECUTE));
-        }
-
-        // Spec says stop() on SystemBundle should return immediately and
-        // shutdown framework on another thread.
-        if (getFelix().getStatus() == Felix.RUNNING_STATUS)
-        {
-            // Initial call of stop, so kick off shutdown.
-            m_shutdownThread = new Thread("FelixShutdown") {
-                public void run()
-                {
-                    try
-                    {
-                        getFelix().shutdown();
-                    }
-                    catch (Exception ex)
-                    {
-                        getFelix().getLogger().log(
-                            Logger.LOG_ERROR,
-                            "SystemBundle: Error while shutting down.", ex);
-                    }
-                }
-            };
-            getInfo().setState(Bundle.STOPPING);
-            m_shutdownThread.start();
-        }
+        super.stop();
     }
 
     public void uninstall() throws BundleException
@@ -228,43 +194,6 @@
         throw new BundleException("System bundle update not implemented yet.");
     }
 
-    protected BundleActivator getActivator()
-    {
-        if (m_activator == null)
-        {
-            m_activator = new SystemBundleActivator(m_activatorList);
-        }
-        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.
-     */
-    void shutdown() throws BundleException
-    {
-        // Callback from shutdown thread, so do our own stop.
-        try
-        {
-            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;
@@ -308,29 +237,6 @@
         }
     }
     
-    void startExtensionBundle(BundleImpl bundle) 
-    {
-        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);
-            }
-        }
-    }
-
     public Object run()
     {
         _addExtensionBundle((BundleImpl) m_tempBundle.get());
@@ -389,6 +295,109 @@
         parseAndAddExports(headers);
 
         systemArchive.setManifestHeader(headers);
+    }
+
+    void startExtensionBundle(BundleImpl bundle)
+    {
+        String activatorClass = (String)
+        bundle.getInfo().getCurrentHeader().get(
+            FelixConstants.FELIX_EXTENSION_ACTIVATOR);
+        
+        if (activatorClass != null)
+        {
+            try
+            {
+                BundleActivator activator = (BundleActivator)
+                    getClass().getClassLoader().loadClass(
+                        activatorClass.trim()).newInstance();
+                m_activatorList.add(activator);
+                if (m_activatorContextMap == null)
+                {
+                    m_activatorContextMap = new HashMap();
+                }
+                BundleContext context = new BundleContextImpl(getFelix(), bundle);
+                m_activatorContextMap.put(activator, context);
+                activator.start(context);
+            }
+            catch (Throwable ex)
+            {
+                getFelix().getLogger().log(Logger.LOG_WARNING,
+                    "Unable to start Felix Extension Activator", ex);
+            }
+        }
+    }
+
+    private class SystemBundleActivator implements BundleActivator, Runnable
+    {
+        public void start(BundleContext context) throws Exception
+        {
+            getInfo().setBundleContext(context);
+
+            // Start all activators.
+            for (int i = 0; i < m_activatorList.size(); i++)
+            {
+                ((BundleActivator) m_activatorList.get(i)).start(context);
+            }
+        }
+
+        public void stop(BundleContext context) throws Exception
+        {
+            getInfo().setBundleContext(context);
+
+            // Spec says stop() on SystemBundle should return immediately and
+            // shutdown framework on another thread.
+            if (getFelix().getStatus() == Felix.RUNNING_STATUS)
+            {
+                // Initial call of stop, so kick off shutdown.
+                m_shutdownThread = new Thread(this, "FelixShutdown");
+                m_shutdownThread.start();
+            }
+        }
+
+        public void run()
+        {
+            // First, stop all other bundles.
+            try
+            {
+                getFelix().shutdownInternal();
+            }
+            catch (Exception ex)
+            {
+                getFelix().getLogger().log(
+                    Logger.LOG_ERROR,
+                    "SystemBundle: Error while shutting down.", ex);
+            }
+
+            // Next, stop all system bundle activators.
+            if (m_activatorList != null)
+            {
+                // Stop all activators.
+                for (int i = 0; i < m_activatorList.size(); i++)
+                {
+                    try
+                    {
+                        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(getInfo().getBundleContext());
+                        }
+                    }
+                    catch (Throwable throwable)
+                    {
+                        getFelix().getLogger().log(
+                            Logger.LOG_WARNING,
+                            "Exception stopping a system bundle activator.",
+                            throwable);
+                    }
+                }
+            }
+        }
     }
 
     private class SystemBundleContentLoader implements IContentLoader

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java?view=diff&rev=543242&r1=543241&r2=543242
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersContentHandlerProxy.java Thu May 31 13:07:11 2007
@@ -103,9 +103,7 @@
         {
             // Get the framework's system bundle context.
             BundleContext context =
-                ((SystemBundleActivator)
-                    ((SystemBundle) framework.getBundle(0)).getActivator())
-                        .getBundleContext();
+                ((BundleImpl) framework.getBundle(0)).getInfo().getBundleContext();
             // Create a filter for the mime type.
             String filter = 
                 "(&(objectClass="

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java?view=diff&rev=543242&r1=543241&r2=543242
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java Thu May 31 13:07:11 2007
@@ -203,9 +203,7 @@
         {
             // Get the framework's system bundle context.
             BundleContext context =
-                ((SystemBundleActivator)
-                    ((SystemBundle) framework.getBundle(0)).getActivator())
-                        .getBundleContext();
+                ((BundleImpl) framework.getBundle(0)).getInfo().getBundleContext();
             // Create a filter for the protocol.
             String filter = 
                 "(&(objectClass="