You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2011/01/06 18:26:58 UTC
svn commit: r1055949 - in /karaf/trunk: main/
main/src/main/java/org/apache/karaf/main/
main/src/test/java/org/apache/karaf/main/
shell/wrapper/src/main/java/org/apache/karaf/shell/wrapper/
Author: gnodet
Date: Thu Jan 6 17:26:57 2011
New Revision: 1055949
URL: http://svn.apache.org/viewvc?rev=1055949&view=rev
Log:
[KARAF-327] Clean up graceful shutdown, make sure the wrapper is informed if the framework is exited through osgi:shutdown
Added:
karaf/trunk/main/src/test/java/org/apache/karaf/main/TimeoutShutdownActivator.java
- copied, changed from r1055859, karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java
Modified:
karaf/trunk/main/pom.xml
karaf/trunk/main/src/main/java/org/apache/karaf/main/Main.java
karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java
karaf/trunk/main/src/test/java/org/apache/karaf/main/MainStartTest.java
karaf/trunk/shell/wrapper/src/main/java/org/apache/karaf/shell/wrapper/Main.java
Modified: karaf/trunk/main/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/main/pom.xml?rev=1055949&r1=1055948&r2=1055949&view=diff
==============================================================================
--- karaf/trunk/main/pom.xml (original)
+++ karaf/trunk/main/pom.xml Thu Jan 6 17:26:57 2011
@@ -51,6 +51,16 @@
<artifactId>org.apache.servicemix.bundles.junit</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.swissbox</groupId>
+ <artifactId>pax-swissbox-tinybundles</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
Modified: karaf/trunk/main/src/main/java/org/apache/karaf/main/Main.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/apache/karaf/main/Main.java?rev=1055949&r1=1055948&r2=1055949&view=diff
==============================================================================
--- karaf/trunk/main/src/main/java/org/apache/karaf/main/Main.java (original)
+++ karaf/trunk/main/src/main/java/org/apache/karaf/main/Main.java Thu Jan 6 17:26:57 2011
@@ -30,7 +30,15 @@ import java.net.URLClassLoader;
import java.security.AccessControlException;
import java.security.Provider;
import java.security.Security;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Random;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -38,7 +46,6 @@ import java.util.regex.Pattern;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.ServiceReference;
@@ -147,6 +154,8 @@ public class Main {
public static final String KARAF_FRAMEWORK = "karaf.framework";
+ public static final String KARAF_SHUTDOWN_TIMEOUT = "karaf.shutdown.timeout";
+
public static final String KARAF_SHUTDOWN_PORT = "karaf.shutdown.port";
public static final String KARAF_SHUTDOWN_HOST = "karaf.shutdown.host";
@@ -177,12 +186,18 @@ public class Main {
private int defaultStartLevel = 100;
private int lockStartLevel = 1;
private int lockDelay = 1000;
+ private int shutdownTimeout = 5 * 60 * 1000;
private boolean exiting = false;
+ private ShutdownCallback shutdownCallback;
public Main(String[] args) {
this.args = args;
}
+ public void setShutdownCallback(ShutdownCallback shutdownCallback) {
+ this.shutdownCallback = shutdownCallback;
+ }
+
public void launch() throws Exception {
karafHome = Utils.getKarafHome();
karafBase = Utils.getKarafDirectory(Main.PROP_KARAF_BASE, Main.ENV_KARAF_BASE, karafHome, false, true);
@@ -229,6 +244,7 @@ public class Main {
lockStartLevel = Integer.parseInt(configProps.getProperty(PROPERTY_LOCK_LEVEL, Integer.toString(lockStartLevel)));
lockDelay = Integer.parseInt(configProps.getProperty(PROPERTY_LOCK_DELAY, Integer.toString(lockDelay)));
configProps.setProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, Integer.toString(lockStartLevel));
+ shutdownTimeout = Integer.parseInt(configProps.getProperty(KARAF_SHUTDOWN_TIMEOUT, Integer.toString(shutdownTimeout)));
// Start up the OSGI framework
InputStream is = classLoader.getResourceAsStream("META-INF/services/" + FrameworkFactory.class.getName());
@@ -247,52 +263,48 @@ public class Main {
}.start();
}
- public void destroy(boolean await) throws Exception {
- destroy(await, 0, null);
- }
+ public void awaitShutdown() throws Exception {
+ while (true) {
+ FrameworkEvent event = framework.waitForStop(0);
+ if (event.getType() != FrameworkEvent.STOPPED_UPDATE) {
+ return;
+ }
+ }
+ }
- public void destroy(boolean await, int timeout, ShutdownCallback callback) throws Exception {
+ public boolean destroy() throws Exception {
if (framework == null) {
- return;
+ return true;
}
try {
- if (await) {
- while (true) {
- FrameworkEvent event;
- if (callback != null) {
- callback.waitingForShutdown();
- event = framework.waitForStop(timeout);
- //do the stoping in an extra thread
- Runnable stopper = new Runnable() {
-
- public void run() {
- try {
-
- framework.stop();
- } catch (BundleException e) {
- System.err.println("Exception while stoping framework: " + e);
- }
- }
- };
- Thread t = new Thread(stopper);
- t.start();
- while (t.getState() != Thread.State.TERMINATED && event.getType() == FrameworkEvent.WAIT_TIMEDOUT) {
- callback.waitingForShutdown();
- event = framework.waitForStop(timeout);
- }
- break;
- } else {
- event = framework.waitForStop(0);
- }
- if (event.getType() != FrameworkEvent.STOPPED_UPDATE) {
- break;
- }
- }
+ int step = 5000;
+
+ // Notify the callback asap
+ if (shutdownCallback != null) {
+ shutdownCallback.waitingForShutdown(step);
}
+
+ // Stop the framework in case it's still active
exiting = true;
if (framework.getState() == Bundle.ACTIVE) {
framework.stop();
}
+
+ int timeout = shutdownTimeout;
+ if (shutdownTimeout <= 0) {
+ timeout = Integer.MAX_VALUE;
+ }
+ while (timeout > 0) {
+ timeout -= step;
+ if (shutdownCallback != null) {
+ shutdownCallback.waitingForShutdown(step * 2);
+ }
+ FrameworkEvent event = framework.waitForStop(step);
+ if (event.getType() != FrameworkEvent.WAIT_TIMEDOUT) {
+ return true;
+ }
+ }
+ return false;
} finally {
unlock();
}
@@ -394,8 +406,17 @@ public class Main {
ex.printStackTrace();
}
try {
- main.destroy(true);
+ main.awaitShutdown();
+ boolean stopped = main.destroy();
restart = Boolean.getBoolean("karaf.restart");
+ if (!stopped) {
+ if (restart) {
+ System.err.println("Timeout waiting for framework to stop. Restarting now.");
+ } else {
+ System.err.println("Timeout waiting for framework to stop. Exiting VM.");
+ main.setExitCode(-3);
+ }
+ }
} catch (Throwable ex) {
main.setExitCode(-2);
System.err.println("Error occured shutting down framework: " + ex);
Modified: karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java?rev=1055949&r1=1055948&r2=1055949&view=diff
==============================================================================
--- karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java (original)
+++ karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java Thu Jan 6 17:26:57 2011
@@ -32,6 +32,6 @@ public interface ShutdownCallback {
* The callback method invoked to inform anyone listening that the
* Main class is still waiting for the completion of the shutdown.
*/
- void waitingForShutdown();
-
+ void waitingForShutdown(int delay);
+
}
Modified: karaf/trunk/main/src/test/java/org/apache/karaf/main/MainStartTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/test/java/org/apache/karaf/main/MainStartTest.java?rev=1055949&r1=1055948&r2=1055949&view=diff
==============================================================================
--- karaf/trunk/main/src/test/java/org/apache/karaf/main/MainStartTest.java (original)
+++ karaf/trunk/main/src/test/java/org/apache/karaf/main/MainStartTest.java Thu Jan 6 17:26:57 2011
@@ -23,9 +23,13 @@ import java.io.File;
import junit.framework.Assert;
import org.junit.Ignore;
import org.junit.Test;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
+import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.withBnd;
+
public class MainStartTest {
@Test
@@ -56,6 +60,38 @@ public class MainStartTest {
Assert.assertEquals(mvnUrl, bundles[2].getLocation());
Assert.assertEquals(Bundle.ACTIVE, bundles[1].getState());
Assert.assertEquals(Bundle.ACTIVE, bundles[2].getState());
- main.destroy(false);
+ main.destroy();
}
+
+ @Test
+ public void testStopWithTimeout() throws Exception {
+ File basedir = new File(getClass().getClassLoader().getResource("foo").getPath()).getParentFile();
+ File home = new File(basedir, "test-karaf-home");
+ File data = new File(home, "data");
+
+ Utils.deleteDirectory(data);
+
+ String[] args = new String[0];
+ System.setProperty("karaf.home", home.toString());
+ System.setProperty("karaf.data", data.toString());
+
+ Main main = new Main(args);
+ main.launch();
+ Thread.sleep(1000);
+ Framework framework = main.getFramework();
+ String activatorName = TimeoutShutdownActivator.class.getName().replace('.', '/') + ".class";
+ Bundle bundle = framework.getBundleContext().installBundle("foo",
+ TinyBundles.newBundle()
+ .set( Constants.BUNDLE_ACTIVATOR, TimeoutShutdownActivator.class.getName() )
+ .add( activatorName, getClass().getClassLoader().getResourceAsStream( activatorName ) )
+ .build( withBnd() )
+ );
+ bundle.start();
+
+ long t0 = System.currentTimeMillis();
+ main.destroy();
+ long t1 = System.currentTimeMillis();
+// System.err.println("Shutdown duration: " + (t1 - t0) + " ms");
+ Assert.assertTrue((t1 - t0) > TimeoutShutdownActivator.TIMEOUT / 2);
+ }
}
Copied: karaf/trunk/main/src/test/java/org/apache/karaf/main/TimeoutShutdownActivator.java (from r1055859, karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java)
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/test/java/org/apache/karaf/main/TimeoutShutdownActivator.java?p2=karaf/trunk/main/src/test/java/org/apache/karaf/main/TimeoutShutdownActivator.java&p1=karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java&r1=1055859&r2=1055949&rev=1055949&view=diff
==============================================================================
--- karaf/trunk/main/src/main/java/org/apache/karaf/main/ShutdownCallback.java (original)
+++ karaf/trunk/main/src/test/java/org/apache/karaf/main/TimeoutShutdownActivator.java Thu Jan 6 17:26:57 2011
@@ -1,37 +1,34 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.main;
-
-
-/**
- * <p>
- * This interface is a callback interface for the stoping process.
- * It's main purpose is to give the ServiceWrapper a way of waiting
- * for the Framework to gracefully stop the Server.
- * <p>
- */
-public interface ShutdownCallback {
-
- /**
- * The callback method invoked to inform anyone listening that the
- * Main class is still waiting for the completion of the shutdown.
- */
- void waitingForShutdown();
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.main;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class TimeoutShutdownActivator implements BundleActivator {
+
+ public static int TIMEOUT = 10000;
+
+ public void start(BundleContext context) throws Exception {
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ Thread.sleep(TIMEOUT);
+ }
+}
Modified: karaf/trunk/shell/wrapper/src/main/java/org/apache/karaf/shell/wrapper/Main.java
URL: http://svn.apache.org/viewvc/karaf/trunk/shell/wrapper/src/main/java/org/apache/karaf/shell/wrapper/Main.java?rev=1055949&r1=1055948&r2=1055949&view=diff
==============================================================================
--- karaf/trunk/shell/wrapper/src/main/java/org/apache/karaf/shell/wrapper/Main.java (original)
+++ karaf/trunk/shell/wrapper/src/main/java/org/apache/karaf/shell/wrapper/Main.java Thu Jan 6 17:26:57 2011
@@ -23,11 +23,10 @@ import org.tanukisoftware.wrapper.Wrappe
/**
* Java Service Wrapper Main class
*/
-public class Main implements WrapperListener, ShutdownCallback {
+public class Main extends Thread implements WrapperListener, ShutdownCallback {
- private static final int TIMEOUT = 1000; //wainting timeout for a second should be enough
- private static final int TIMEOUT_OFFSET = 500; // the offset for the wrapper, to leave us some time to breath
- private org.apache.karaf.main.Main main;
+ private org.apache.karaf.main.Main main;
+ private volatile boolean destroying;
/*---------------------------------------------------------------
* Constructors
@@ -57,6 +56,8 @@ public class Main implements WrapperList
try
{
main.launch();
+ main.setShutdownCallback(this);
+ start();
return null;
}
catch (Throwable ex)
@@ -65,7 +66,17 @@ public class Main implements WrapperList
ex.printStackTrace();
return -1;
}
+ }
+ public void run() {
+ try {
+ main.awaitShutdown();
+ if (!destroying) {
+ WrapperManager.stop(main.getExitCode());
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
}
/**
@@ -88,7 +99,8 @@ public class Main implements WrapperList
{
try
{
- main.destroy(true, TIMEOUT, this);
+ destroying = true;
+ main.destroy();
}
catch (Throwable ex)
{
@@ -97,15 +109,15 @@ public class Main implements WrapperList
return -2;
}
- return exitCode;
+ return main.getExitCode();
}
/**
* Call-back method is called by the @{link org.apache.karaf.main.Main} for Signaling
* that the stopping process is in progress and the wrapper doesn't kill the JVM.
*/
- public void waitingForShutdown() {
- WrapperManager.signalStopping(TIMEOUT + TIMEOUT_OFFSET);
+ public void waitingForShutdown(int delay) {
+ WrapperManager.signalStopping(delay);
}
/**