2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 import java
.io
.InputStream
;
22 import java
.io
.OutputStreamWriter
;
23 import java
.io
.UnsupportedEncodingException
;
24 import java
.io
.PrintWriter
;
25 import java
.io
.PrintStream
;
26 import java
.io
.LineNumberReader
;
27 import java
.io
.InputStreamReader
;
31 * Class collect information from input stream in
32 * background (separate thread) and outputs it to
33 * some log stream. I helps to avoid buffer overflow
34 * when output stream has small buffer size (e.g.
35 * in case when handling stdout from external
36 * <code>Process</code>)
38 * This class is currently used by ProcessHandler
41 class Pump
extends Thread
44 private final LineNumberReader reader
;
45 private final String pref
;
46 private final StringBuffer buf
= new StringBuffer(256);
47 private final PrintWriter log
;
48 private final boolean bOutput
;
51 * Creates Pump for specified <code>InputStream</code>.
52 * This Pump also synchronously output text read to
53 * log by prefixed lines. Constructor immediately
54 * starts reading in a separate thread.
56 * @param is Stream which requires permanent reading.
57 * @param log Writer where prefixed text lines to be output
58 * @param outPrefix A prefix which is printed at the
59 * beginning of each output line.
61 public Pump(InputStream is
, PrintWriter log
, String outPrefix
, boolean _bOutput
)
63 this.pref
= (outPrefix
== null) ?
"" : outPrefix
;
64 reader
= new LineNumberReader(new InputStreamReader(is
));
66 this.bOutput
= _bOutput
;
75 String line
= reader
.readLine();
80 log
.println(pref
+ line
);
83 buf
.append(line
).append('\n');
84 line
= reader
.readLine();
87 catch (java
.io
.IOException e
)
89 log
.println(pref
+ "Exception occurred: " + e
);
94 * Returns the text collected from input stream.
96 public String
getStringBuffer()
98 return buf
.toString();
103 * Class provides convenient way for running external program
104 * handle its standard streams, control execution and check results.
105 * Instance of this class must be created only for a single
106 * execution. If you need to execute the same command again you
107 * should create a new instance for this.
109 public class ProcessHandler
111 private String cmdLine
;
112 private String
[] envVars
= null;
113 private File workDir
= null;
114 private PrintWriter log
;
115 private int exitValue
= -1;
116 private boolean isStarted
= false;
117 private PrintStream stdIn
= null;
118 private Process m_aProcess
= null;
119 private boolean debug
= false;
120 private boolean bUseOutput
= true;
123 * Creates instance with specified external command and
124 * log stream where debug info and output
125 * of external command is printed out.
127 public ProcessHandler(String cmdLine
, PrintWriter log
) throws UnsupportedEncodingException
129 this(cmdLine
, log
, null, null);
133 * Creates instance with specified external command which
134 * will be executed in the same work directory and
136 * @param cmdLine the command to be executed
137 * @param log log stream where debug info and output
138 * of external command is printed .
139 * @param workDir The working directory of the new process
140 * @param envVars The specified environment variables are
141 * set for the new process.
142 * If log stream is null, logging is printed to stdout.
143 * @param timeOut When started synchronously, the maximum time the
144 * process will live. When the process being destroyed
145 * a log will be written out. It can be asked on
146 * <code>isTimedOut()</code> if it has been terminated.
149 * Waits specified time in milliSeconds for
150 * process to exit and return its status.
153 * Waits for the process to end regularly
156 private ProcessHandler(String cmdLine
, PrintWriter log
, File workDir
, String
[] envVars
) throws UnsupportedEncodingException
158 this.cmdLine
= cmdLine
;
159 this.workDir
= workDir
;
161 this.envVars
= envVars
;
164 this.log
= new PrintWriter(new OutputStreamWriter(System
.out
, "UTF-8"));
173 * Executes the command immediately returns. The process
174 * remains in running state.
176 * @return <code>true</code> if process was successfully
179 public boolean executeAsynchronously()
185 public synchronized void kill()
191 boolean exit
= false;
193 while (counter
< 3 && !exit
)
195 m_aProcess
.destroy();
197 util
.utils
.pause(1000 * counter
);
200 final int exit_Value
= m_aProcess
.exitValue();
209 dbg("kill: process closed with exit code " + exit_Value
);
211 catch (java
.lang
.IllegalThreadStateException e
)
215 dbg("kill: Couldn't close process after " + counter
+ " attempts, trying again");
223 private void showEnvVars()
227 for (int i
= 0; i
< envVars
.length
; i
++)
229 log
.println("env: " + envVars
[i
]);
234 log
.println("env: null");
238 private void execute()
242 throw new RuntimeException(
243 "The process handler has already been executed.");
245 final Runtime runtime
= Runtime
.getRuntime();
250 log
.println(utils
.getDateTime() + "execute: Starting command: ");
251 log
.println(cmdLine
+ " path=" + workDir
.getAbsolutePath());
253 m_aProcess
= runtime
.exec(cmdLine
, envVars
, workDir
);
257 log
.println(utils
.getDateTime() + "execute: Starting command: ");
258 log
.println(cmdLine
);
260 m_aProcess
= runtime
.exec(cmdLine
, envVars
);
264 catch (java
.io
.IOException e
)
266 log
.println(utils
.getDateTime() + "execute: The command " + cmdLine
+ " can't be started: " + e
);
269 dbg("execute: pump io-streams");
270 new Pump(m_aProcess
.getInputStream(), log
, "out > ", bUseOutput
);
271 new Pump(m_aProcess
.getErrorStream(), log
, "err > ", bUseOutput
);
272 stdIn
= new PrintStream(m_aProcess
.getOutputStream());
274 dbg("execute: flush io-streams");
279 private void flushInput()
293 * Returns information about was the command started or
296 * @return <code>true</code> if the external command was
297 * found and successfully started.
299 private boolean isStarted()
305 * Returns exit code of the external command.
307 * @return exit code of command if it was finished,
310 public int getExitCode()
314 exitValue
= m_aProcess
.exitValue();
323 private void dbg(String message
)
327 log
.println(utils
.getDateTime() + "PH." + message
);