Commits

Anonymous committed 2c9b196

Issue number: QUARTZ-257
Obtained from:
Submitted by:
Reviewed by:
CVS: ----------------------------------------------------------------------
CVS: Issue number:
CVS: If this change addresses one or more issues,
CVS: then enter the issue number(s) here.
CVS: Obtained from:
CVS: If this change has been taken from another system,
CVS: then name the system in this line, otherwise delete it.
CVS: Submitted by:
CVS: If this code has been contributed to the project by someone else; i.e.,
CVS: they sent us a patch or a set of diffs, then include their name/email
CVS: address here. If this is your work then delete this line.
CVS: Reviewed by:
CVS: If we are doing pre-commit code reviews and someone else has
CVS: reviewed your changes, include their name(s) here.
CVS: If you have not had it reviewed then delete this line.

git-svn-id: http://svn.opensymphony.com/svn/quartz/trunk@26669f7d36a-ea1c-0410-88ea-9fd03e4c9665

Comments (0)

Files changed (1)

src/java/org/quartz/jobs/NativeJob.java

 
 package org.quartz.jobs;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.quartz.Job;
 import org.quartz.JobDataMap;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
 
-
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.logging.Log;
-
 /*
  * <p> Built in job for executing native executables in a separate process.</p> 
  * 
- * @author Matthew payne
+ * 
+ * @see #PROP_COMMAND
+ * @see #PROP_PARAMETERS
+ * @see #PROP_WAIT_FOR_PROCESS
+ * @see #PROP_CONSUME_STREAMS
+ * 
+ * @author Matthew Payne
  * @author James House
+ * @author Steinar Overbeck Cook
  * @date Sep 17, 2003 @Time: 11:27:13 AM
  */
 public class NativeJob implements Job {
      */
     public static final String PROP_WAIT_FOR_PROCESS = "waitForProcess";
     
+    /**
+     * Optional parameter (value should be 'true' or 'false') that specifies 
+     * whether the spawned process's stdout and stderr streams should be 
+     * consumed.  If the process creates output, it is possible that it might
+     * 'hang' if the streams are not consumed.
+     * 
+     * <p>Defaults to <code>false</code>.</p>  
+     */
+    public static final String PROP_CONSUME_STREAMS = "consumeStreams";
+    
     
     /*
      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         }
 
         boolean wait = true;
-        if(data.containsKey(PROP_WAIT_FOR_PROCESS))
-            wait = data.getBoolean(PROP_WAIT_FOR_PROCESS);            
+        if(data.containsKey(PROP_WAIT_FOR_PROCESS)) {
+            wait = data.getBooleanValue(PROP_WAIT_FOR_PROCESS);
+        }
+        boolean consumeStreams = false;
+        if(data.containsKey(PROP_CONSUME_STREAMS)) {
+            consumeStreams = data.getBooleanValue(PROP_CONSUME_STREAMS);
+        }
             
-        this.runNativeCommand(command, parameters, wait);
+        this.runNativeCommand(command, parameters, wait, consumeStreams);
     }
 
     private static Log getLog()
         return LogFactory.getLog(NativeJob.class);
     }
     
-    private void runNativeCommand(String command, String parameters, boolean wait) throws JobExecutionException {
+    private void runNativeCommand(String command, String parameters, boolean wait, boolean consumeStreams) throws JobExecutionException {
 
         String[] cmd = null;
         String[] args = new String[2];
             // Executes the command
             getLog().info("About to run" + cmd[0] + cmd[1]);
             Process proc = rt.exec(cmd);
+            // Consumes the stdout from the process
+            StreamConsumer stdoutConsumer = new StreamConsumer(proc.getInputStream(), "stdout");
+
+            // Consumes the stderr from the process
+            if(consumeStreams) {
+                StreamConsumer stderrConsumer = new StreamConsumer(proc.getErrorStream(), "stderr");
+                stdoutConsumer.start();
+                stderrConsumer.start();
+            }
+            
             if(wait)
                 proc.waitFor(); 
             // any error message?
-
             
         } catch (Exception x) {
-            System.out.println("error happened in native job");
             throw new JobExecutionException("Error launching native command: ", x, false);
         }
     }
 
+    /**
+     * Consumes data from the given input stream until EOF and prints the data to stdout
+     *
+     * @author cooste
+     * @author jhouse
+     */
+    class StreamConsumer extends Thread {
+        InputStream is;
+        String type;
+
+        /**
+         *
+         */
+        public StreamConsumer(InputStream inputStream, String type) {
+            this.is = inputStream;
+            this.type = type;
+        }
+
+        /**
+         * Runs this object as a separate thread, printing the contents of the InputStream
+         * supplied during instantiation, to either stdout or stderr
+         */
+        public void run() {
+            BufferedReader br = null;
+            try {
+                br = new BufferedReader(new InputStreamReader(is));
+                String line = null;
+
+                while ((line = br.readLine()) != null) {
+                    if(type.equalsIgnoreCase("stderr"))
+                        getLog().warn(type + ">" + line);
+                    else
+                        getLog().info(type + ">" + line);
+                }
+            } catch (IOException ioe) {
+                getLog().error("Error consuming " + type + " stream of spawned process.", ioe);
+            }
+            finally {
+                if(br != null)
+                    try { br.close(); } catch(Exception ignore) {}
+            }
+        }
+    }
+    
 }