Bump version to 24.04.3.4
[LibreOffice.git] / qadevOOo / runner / helper / ProcessHandler.java
blob26c1f787519f13053d068a488a0cc0c73ec3574e
1 /*
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 .
18 package helper;
20 import java.io.InputStream;
21 import java.io.File;
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;
28 import util.utils;
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
39 * internally only.
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;
50 /**
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));
65 this.log = log;
66 this.bOutput = _bOutput;
67 start();
70 @Override
71 public void run()
73 try
75 String line = reader.readLine();
76 while (line != null)
78 if (bOutput)
80 log.println(pref + line);
81 log.flush();
83 buf.append(line).append('\n');
84 line = reader.readLine();
87 catch (java.io.IOException e)
89 log.println(pref + "Exception occurred: " + e);
93 /**
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.
148 * timeOut > 0
149 * Waits specified time in milliSeconds for
150 * process to exit and return its status.
152 * timeOut = 0
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;
160 this.log = log;
161 this.envVars = envVars;
162 if (log == null)
164 this.log = new PrintWriter(new OutputStreamWriter(System.out, "UTF-8"));
166 else
168 this.log = log;
173 * Executes the command immediately returns. The process
174 * remains in running state.
176 * @return <code>true</code> if process was successfully
177 * started.
179 public boolean executeAsynchronously()
181 execute();
182 return isStarted();
185 public synchronized void kill()
187 if (!isStarted())
189 return;
191 boolean exit = false;
192 int counter = 1;
193 while (counter < 3 && !exit)
195 m_aProcess.destroy();
197 util.utils.pause(1000 * counter);
200 final int exit_Value = m_aProcess.exitValue();
201 if (exit_Value < 1)
203 exit = true;
205 else
207 counter++;
209 dbg("kill: process closed with exit code " + exit_Value);
211 catch (java.lang.IllegalThreadStateException e)
213 if (counter < 3)
215 dbg("kill: Couldn't close process after " + counter + " attempts, trying again");
217 counter++;
220 isStarted = false;
223 private void showEnvVars()
225 if (envVars != null)
227 for (int i = 0; i < envVars.length; i++)
229 log.println("env: " + envVars[i]);
232 else
234 log.println("env: null");
238 private void execute()
240 if (isStarted())
242 throw new RuntimeException(
243 "The process handler has already been executed.");
245 final Runtime runtime = Runtime.getRuntime();
248 if (workDir != null)
250 log.println(utils.getDateTime() + "execute: Starting command: ");
251 log.println(cmdLine + " path=" + workDir.getAbsolutePath());
252 showEnvVars();
253 m_aProcess = runtime.exec(cmdLine, envVars, workDir);
255 else
257 log.println(utils.getDateTime() + "execute: Starting command: ");
258 log.println(cmdLine);
259 showEnvVars();
260 m_aProcess = runtime.exec(cmdLine, envVars);
262 isStarted = true;
264 catch (java.io.IOException e)
266 log.println(utils.getDateTime() + "execute: The command " + cmdLine + " can't be started: " + e);
267 return;
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");
276 flushInput();
279 private void flushInput()
281 if (stdIn == null)
283 return;
286 synchronized(this)
288 stdIn.flush();
293 * Returns information about was the command started or
294 * not.
296 * @return <code>true</code> if the external command was
297 * found and successfully started.
299 private boolean isStarted()
301 return isStarted;
305 * Returns exit code of the external command.
307 * @return exit code of command if it was finished,
308 * -1 if not.
310 public int getExitCode()
314 exitValue = m_aProcess.exitValue();
316 catch (Exception e)
320 return exitValue;
323 private void dbg(String message)
325 if (debug)
327 log.println(utils.getDateTime() + "PH." + message);