MATSIM
ExeRunner.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * ExeRunner.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007, 2008 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.core.utils.misc;
22 
23 import java.io.BufferedReader;
24 import java.io.BufferedWriter;
25 import java.io.File;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.OutputStreamWriter;
30 import java.io.PrintStream;
31 import java.util.Arrays;
32 
33 import org.apache.logging.log4j.LogManager;
34 import org.apache.logging.log4j.Logger;
35 
36 
42 public abstract class ExeRunner {
43 
44  /*package*/ final static Logger log = LogManager.getLogger(ExeRunner.class);
45 
56  public static int run(final String cmd, final String stdoutFileName, final int timeout) {
57  return run(cmd, stdoutFileName, timeout, null);
58  }
59 
60  public static int run(final String[] cmdArgs, final String stdoutFileName, final int timeout) {
61  return run(cmdArgs, stdoutFileName, timeout, null);
62  }
63 
75  public static int run(final String cmd, final String stdoutFileName, final int timeout, final String workingDirectory) {
76  final ExternalExecutor myExecutor = new ExternalExecutor(cmd, stdoutFileName, workingDirectory);
77  return waitForFinish(myExecutor, timeout);
78  }
79 
80  public static int run(final String[] cmdArgs, final String stdoutFileName, final int timeout, final String workingDirectory) {
81  final ExternalExecutor myExecutor = new ExternalExecutor(cmdArgs, stdoutFileName, workingDirectory);
82  return waitForFinish(myExecutor, timeout);
83  }
84 
85  public static int waitForFinish(final ExternalExecutor myExecutor, final int timeout) {
86  synchronized (myExecutor) {
87  try {
88  long timeoutMillis = 1000L * timeout;
89  long startTime = System.currentTimeMillis();
90  myExecutor.start();
91  while (System.currentTimeMillis() - startTime < timeoutMillis) {
92  // reduce the timeout to the residual of the timeout
93  timeoutMillis -= System.currentTimeMillis() - startTime;
94  myExecutor.wait(timeoutMillis);
95  // wait can return for different reasons
96  if (myExecutor.getState().equals(Thread.State.TERMINATED)) {
97  break;
98  }
99  }
100  if (!myExecutor.getState().equals(Thread.State.TERMINATED)) {
101  myExecutor.timeout = true;
102  myExecutor.interrupt();
103  myExecutor.join();
104  }
105  } catch (InterruptedException e) {
106  log.info("ExeRunner.run() got interrupted while waiting for timeout", e);
107  }
108  }
109 
110  return myExecutor.erg;
111  }
112 
113  private static class ExternalExecutor extends Thread {
114  final String cmd;
115  final String[] cmdArgs;
116  final String stdoutFileName;
117  final String stderrFileName;
118  final String workingDirectory;
119  private Process p = null;
120  public volatile boolean timeout = false;
121 
122  public int erg = -1;
123 
124  public ExternalExecutor (final String cmd, final String stdoutFileName, final String workingDirectory) {
125  this.cmd = cmd;
126  this.cmdArgs = null;
127  this.stdoutFileName = stdoutFileName;
128  this.workingDirectory = workingDirectory;
129  if (stdoutFileName != null) {
130  if (stdoutFileName.endsWith(".log")) {
131  this.stderrFileName = stdoutFileName.substring(0, stdoutFileName.length() - 4) + ".err";
132  } else {
133  this.stderrFileName = stdoutFileName + ".err";
134  }
135  } else {
136  this.stderrFileName = null;
137  }
138  }
139 
140  public ExternalExecutor (final String[] cmdArgs, final String stdoutFileName, final String workingDirectory) {
141  this.cmdArgs = cmdArgs;
142  this.cmd = null;
143  this.stdoutFileName = stdoutFileName;
144  this.workingDirectory = workingDirectory;
145  if (stdoutFileName != null) {
146  if (stdoutFileName.endsWith(".log")) {
147  this.stderrFileName = stdoutFileName.substring(0, stdoutFileName.length() - 4) + ".err";
148  } else {
149  this.stderrFileName = stdoutFileName + ".err";
150  }
151  } else {
152  this.stderrFileName = null;
153  }
154  }
155 
156  public void killProcess() {
157  if (this.p != null) {
158  this.p.destroy();
159  }
160  }
161 
162  @Override
163  public void run() {
164  try {
165  if (this.workingDirectory == null) {
166  if (this.cmd != null) {
167  this.p = Runtime.getRuntime().exec(this.cmd);
168  } else if (this.cmdArgs != null) {
169  this.p = Runtime.getRuntime().exec(this.cmdArgs);
170  }
171  } else {
172  if (this.cmd != null) {
173  this.p = Runtime.getRuntime().exec(this.cmd, null, new File(this.workingDirectory));
174  } else if (this.cmdArgs != null) {
175  this.p = Runtime.getRuntime().exec(this.cmdArgs, null, new File(this.workingDirectory));
176  }
177  }
178 
179  BufferedReader in = new BufferedReader(new InputStreamReader(this.p.getInputStream()));
180  BufferedReader err = new BufferedReader(new InputStreamReader(this.p.getErrorStream()));
181 
182  BufferedWriter writerIn = null;
183  StreamHandler outputHandler = null;
184  if (this.stdoutFileName != null) {
185  writerIn = new BufferedWriter(new FileWriter(this.stdoutFileName));
186  outputHandler = new StreamHandler(in, writerIn);
187  outputHandler.start();
188  } else {
189  new BlackHoleStreamHandler(in).start();
190  }
191  BufferedWriter writerErr = null;
192  StreamHandler errorHandler = null;
193  if (this.stderrFileName != null) {
194  writerErr = new BufferedWriter(new FileWriter(this.stderrFileName));
195  errorHandler = new StreamHandler(err, writerErr);
196  errorHandler.start();
197  } else {
198  new BlackHoleStreamHandler(err).start();
199  }
200  log.info("Starting external exe with command: " + (this.cmd != null ? this.cmd : Arrays.toString(this.cmdArgs)));
201  log.info("Output of the externel exe is written to: " + this.stdoutFileName);
202  boolean processRunning = true;
203  while (processRunning && !this.timeout) {
204  try {
205  this.p.waitFor();
206  this.erg = this.p.exitValue();
207  log.info("external exe returned " + this.erg);
208  processRunning = false;
209  } catch (InterruptedException e) {
210  log.info("Thread waiting for external exe to finish was interrupted");
211  this.erg = -3;
212  }
213  }
214  if (this.timeout) {
215  log.info("Timeout reached, killing process...");
216  killProcess();
217  }
218  if (outputHandler != null) {
219  try {
220  outputHandler.join();
221  } catch (InterruptedException e) {
222  log.info("got interrupted while waiting for outputHandler to die.", e);
223  }
224  }
225  if (errorHandler != null) {
226  try {
227  errorHandler.join();
228  } catch (InterruptedException e) {
229  log.info("got interrupted while waiting for errorHandler to die.", e);
230  }
231  }
232  if (writerIn != null) {
233  writerIn.flush();
234  writerIn.close();
235  }
236  if (writerErr != null) {
237  writerErr.flush();
238  writerErr.close();
239  }
240  } catch (IOException e) {
241  log.error("problem running exe", e);
242  this.erg = -2;
243  }
244  }
245  }
246 
247  static class BlackHoleStreamHandler extends Thread {
248  private final BufferedReader in;
249 
250  public BlackHoleStreamHandler(final BufferedReader in) {
251  this.in = in;
252  }
253 
254  @Override
255  public void run() {
256  try {
257  String line = null;
258  while ((line = this.in.readLine()) != null) {
259  }
260  } catch (IOException e) {
261  log.info("StreamHandler got interrupted", e);
262  }
263  }
264  }
265 
266  static class StreamHandler extends Thread {
267  private final BufferedReader in;
268  private final BufferedWriter out;
269 
270  public StreamHandler(final BufferedReader in) {
271  this(in, new BufferedWriter(new OutputStreamWriter(System.out)));
272  }
273 
274  public StreamHandler(final BufferedReader in, final PrintStream out) {
275  this(in, new BufferedWriter(new OutputStreamWriter(out)));
276  }
277 
278  public StreamHandler(final BufferedReader in, final BufferedWriter out) {
279  this.in = in;
280  this.out = out;
281  }
282 
283  @Override
284  public void run() {
285  try {
286  String line = null;
287  while ((line = this.in.readLine()) != null) {
288  this.out.write(line);
289  this.out.write("\n");
290  }
291  this.out.flush();
292  } catch (IOException e) {
293  log.info("StreamHandler got interrupted", e);
294  }
295  }
296  }
297 
298 }
ExternalExecutor(final String cmd, final String stdoutFileName, final String workingDirectory)
Definition: ExeRunner.java:124
static int run(final String cmd, final String stdoutFileName, final int timeout)
Definition: ExeRunner.java:56
static int run(final String cmd, final String stdoutFileName, final int timeout, final String workingDirectory)
Definition: ExeRunner.java:75
static int run(final String[] cmdArgs, final String stdoutFileName, final int timeout)
Definition: ExeRunner.java:60
static int run(final String[] cmdArgs, final String stdoutFileName, final int timeout, final String workingDirectory)
Definition: ExeRunner.java:80
static int waitForFinish(final ExternalExecutor myExecutor, final int timeout)
Definition: ExeRunner.java:85
ExternalExecutor(final String[] cmdArgs, final String stdoutFileName, final String workingDirectory)
Definition: ExeRunner.java:140