incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bdelacre...@apache.org
Subject svn commit: r1235065 - in /sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec: JarExecutor.java ShutdownHookSingleProcessDestroyer.java
Date Mon, 23 Jan 2012 23:36:43 GMT
Author: bdelacretaz
Date: Mon Jan 23 23:36:43 2012
New Revision: 1235065

URL: http://svn.apache.org/viewvc?rev=1235065&view=rev
Log:
SLING-2368 - JarExecutor.stop() waits for the process that it destroys

Added:
    sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java
  (with props)
Modified:
    sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/JarExecutor.java

Modified: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/JarExecutor.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/JarExecutor.java?rev=1235065&r1=1235064&r2=1235065&view=diff
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/JarExecutor.java
(original)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/JarExecutor.java
Mon Jan 23 23:36:43 2012
@@ -27,9 +27,7 @@ import org.apache.commons.exec.DefaultEx
 import org.apache.commons.exec.ExecuteException;
 import org.apache.commons.exec.ExecuteResultHandler;
 import org.apache.commons.exec.Executor;
-import org.apache.commons.exec.ProcessDestroyer;
 import org.apache.commons.exec.PumpStreamHandler;
-import org.apache.commons.exec.ShutdownHookProcessDestroyer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,6 +44,8 @@ public class JarExecutor {
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     public static final int DEFAULT_PORT = 8765;
+    public static final int DEFAULT_EXIT_TIMEOUT = 30;
+    
     public static final String DEFAULT_JAR_FOLDER = "target/dependency";
     public static final String DEFAULT_JAR_NAME_REGEXP = "org.apache.sling.*jar$";
     public static final String PROP_PREFIX = "jar.executor.";
@@ -55,6 +55,7 @@ public class JarExecutor {
     public static final String PROP_VM_OPTIONS = PROP_PREFIX + "vm.options";
     public static final String PROP_WORK_FOLDER = PROP_PREFIX + "work.folder";
     public static final String PROP_JAR_OPTIONS = PROP_PREFIX + "jar.options";
+    public static final String PROP_EXIT_TIMEOUT_SECONDS = PROP_PREFIX + "exit.timeout.seconds";
     
     @SuppressWarnings("serial")
     public static class ExecutorException extends Exception {
@@ -161,28 +162,27 @@ public class JarExecutor {
             executor.setWorkingDirectory(workFolder);
         }
 
+        String tmStr = config.getProperty(PROP_EXIT_TIMEOUT_SECONDS);
+        final int exitTimeoutSeconds = tmStr == null ? DEFAULT_EXIT_TIMEOUT : Integer.valueOf(tmStr);
+
         log.info("Executing " + cl);
         executor.setStreamHandler(new PumpStreamHandler());
-        executor.setProcessDestroyer(getProcessDestroyer());
+        executor.setProcessDestroyer(
+                new ShutdownHookSingleProcessDestroyer("java -jar " + jarToExecute.getName(),
exitTimeoutSeconds));
         executor.execute(cl, h);
     }
     
-    /** Can be overridden to return a custom ProcessDestroyer */
-    protected ProcessDestroyer getProcessDestroyer() {
-        return new ShutdownHookProcessDestroyer();
-    }
-    
-    /** Stop the process that we started, if any */
+    /** Stop the process that we started, if any, and wait for it to exit before returning
*/
     public void stop() {
         if(executor == null) {
             throw new IllegalStateException("Process not started, no Executor set");
         }
         final Object d = executor.getProcessDestroyer();
-        if(d instanceof Runnable) {
-            ((Runnable)d).run();
+        if(d instanceof ShutdownHookSingleProcessDestroyer) {
+            ((ShutdownHookSingleProcessDestroyer)d).destroyProcess(true);
             log.info("Process destroyed");
         } else {
             throw new IllegalStateException(d + " is not a Runnable, cannot destroy process");
         }
     }
-}
+}
\ No newline at end of file

Added: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java
URL: http://svn.apache.org/viewvc/sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java?rev=1235065&view=auto
==============================================================================
--- sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java
(added)
+++ sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java
Mon Jan 23 23:36:43 2012
@@ -0,0 +1,110 @@
+/*
+ * 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.sling.testing.tools.jarexec;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.commons.exec.ProcessDestroyer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Simple ProcessDestroyer for a single process, meant to be used
+ *  with our JarExecutor. 
+ */
+class ShutdownHookSingleProcessDestroyer implements ProcessDestroyer, Runnable {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private Thread shutdownHookThread;
+    private Process process;
+    private final int timeoutSeconds;
+    private final String processInfo;
+    
+    ShutdownHookSingleProcessDestroyer(String processInfo, int timeoutSeconds) {
+        this.processInfo = processInfo;
+        this.timeoutSeconds = timeoutSeconds;
+    }
+    
+    public synchronized boolean add(Process p) {
+        if(process != null) {
+            throw new IllegalStateException("Process already set: " + process);
+        }
+        
+        if(shutdownHookThread == null) {
+            shutdownHookThread = new Thread(this, getClass().getSimpleName());
+            Runtime.getRuntime().addShutdownHook(shutdownHookThread);
+        }
+        
+        process = p;
+        return true;
+    }
+
+    public synchronized boolean remove(Process p) {
+        p = null;
+        return true;
+    }
+
+    public int size() {
+        return 1;
+    }
+    
+    public void run() {
+        // Do not wait for our process when running as a shutdown
+        // hook - might cause trouble
+        destroyProcess(false);
+    }
+    
+   public void destroyProcess(boolean waitForIt) {
+       Process toDestroy = null;
+       synchronized (this) {
+           toDestroy = process;
+           process = null;
+       }
+       
+       if(toDestroy == null) {
+           return;
+       }
+       
+       toDestroy.destroy();
+       
+       if(waitForIt) {
+           log.info("Waiting for destroyed process {} to exit (timeout={} seconds)", processInfo,
timeoutSeconds);
+           final Thread mainThread = Thread.currentThread();
+           final Timer t = new Timer(true);
+           final TimerTask task = new TimerTask() {
+                @Override
+                public void run() {
+                    mainThread.interrupt();
+                }
+           };
+           t.schedule(task, timeoutSeconds * 1000L);
+           try {
+               toDestroy.waitFor();
+               try {
+                   final int exit = toDestroy.exitValue();
+                   log.info("Process {} ended with exit code {}", processInfo, exit);
+               } catch(IllegalStateException ise) {
+                   log.error("Failed to destroy process " + processInfo);
+               }
+           } catch (InterruptedException e) {
+               log.error("Timeout waiting for process " + processInfo + " to exit");
+            } finally {
+                t.cancel();
+            }
+       }
+   }
+}
\ No newline at end of file

Propchange: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/testing/tools/src/main/java/org/apache/sling/testing/tools/jarexec/ShutdownHookSingleProcessDestroyer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL



Mime
View raw message