Applied patch (FELIX-169) to fix how framework shutdown is handled, making
it more symmetric to system start up.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@472017 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 9860cbc..07f8c2c 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -341,8 +341,7 @@
// Create a simple bundle info for the system bundle.
BundleInfo info = new BundleInfo(
m_logger, new SystemBundleArchive(), null);
- systembundle = new SystemBundle(this, info, activatorList,
- m_secureAction);
+ systembundle = new SystemBundle(this, info, activatorList);
// Create a module for the system bundle.
IModuleDefinition md = new ModuleDefinition(
systembundle.getExports(), null, null, null);
@@ -522,6 +521,35 @@
// 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);
+ }
+
+ // 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);
+ }
+ }
+
+ /**
+ * This method actually performs the real shutdown operations of the
+ * framework in terms of setting the start level to zero, really stopping
+ * the system bundle, cleaning up any bundle remains and shutting down event
+ * dispatching.
+ */
+ private void shutdownInternal()
+ {
// 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
@@ -542,9 +570,12 @@
// 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
{
- getBundle(0).stop();
+ ((SystemBundle) getBundle(0)).shutdown();
}
catch (Exception ex)
{
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 b19a6c5..bcde5cb 100644
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
+++ b/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
@@ -34,15 +34,11 @@
private Thread m_shutdownThread = null;
private R4Export[] m_exports = null;
private IContentLoader m_contentLoader = null;
- private SecureAction m_secureAction = null;
- protected SystemBundle(Felix felix, BundleInfo info, List activatorList,
- SecureAction secureAction) throws BundleException
+ protected SystemBundle(Felix felix, BundleInfo info, List activatorList)
{
super(felix, info);
- m_secureAction = secureAction;
-
// Create an activator list if necessary.
if (activatorList == null)
{
@@ -162,7 +158,13 @@
// This will be done after the framework is initialized.
}
- public synchronized void stop() throws BundleException
+ /**
+ * 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 synchronized void stop()
{
Object sm = System.getSecurityManager();
@@ -190,35 +192,11 @@
Logger.LOG_ERROR,
"SystemBundle: Error while shutting down.", ex);
}
-
- // Only shutdown the JVM if the framework is running stand-alone.
- String embedded = getFelix().getConfig()
- .get(FelixConstants.EMBEDDED_EXECUTION_PROP);
- boolean isEmbedded = (embedded == null)
- ? false : embedded.equals("true");
- if (!isEmbedded)
- {
- m_secureAction.exit(0);
- }
}
};
getInfo().setState(Bundle.STOPPING);
m_shutdownThread.start();
}
- else if ((getFelix().getStatus() == Felix.STOPPING_STATUS) &&
- (Thread.currentThread() == m_shutdownThread))
- {
- // Callback from shutdown thread, so do our own stop.
- try
- {
- getActivator().stop(getInfo().getContext());
- }
- catch (Throwable throwable)
- {
- throw new BundleException(
- "Unable to stop system bundle.", throwable);
- }
- }
}
public synchronized void uninstall() throws BundleException
@@ -253,4 +231,26 @@
}
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
+ {
+ getActivator().stop(getInfo().getContext());
+ }
+ catch (Throwable throwable)
+ {
+ throw new BundleException( "Unable to stop system bundle.", throwable );
+ }
+ }
+}
\ No newline at end of file