org.opencastproject.util.ProcessExecutor Maven / Gradle / Ivy
/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.util;
import static org.opencastproject.util.data.Collections.map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Helper class to execute processes on the host system and outside of the java vm. Since there are problems with
* reading stdin, stdout and stderr that need to be taken into account when running on various platforms, this helper
* class is used to deal with those.
*
* A generic Exception should be used to indicate what types of checked exceptions might be thrown from this process.
*
* @deprecated use {@link ProcessRunner} instead
*/
public class ProcessExecutor {
/** The logging facility */
private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
private final boolean redirectErrorStream;
private final String[] commandLine;
private final Map environment;
protected ProcessExecutor(String commandLine, Map environment, boolean redirectErrorStream) {
this.commandLine = commandLine.split("\\s+");
this.environment = environment;
this.redirectErrorStream = redirectErrorStream;
}
protected ProcessExecutor(String command, String options) {
this.commandLine = mkCommandLine(command, options);
this.environment = map();
this.redirectErrorStream = false;
}
protected ProcessExecutor(String command, String[] options) {
List commandLineList = new ArrayList();
commandLineList.add(command);
commandLineList.addAll(Arrays.asList(options));
this.commandLine = commandLineList.toArray(new String[commandLineList.size()]);
this.environment = map();
this.redirectErrorStream = false;
}
protected ProcessExecutor(String[] commandLine) {
this.commandLine = commandLine;
this.environment = map();
this.redirectErrorStream = false;
}
protected ProcessExecutor(String commandLine, boolean redirectErrorStream) {
this.commandLine = commandLine.split("\\s+");
this.redirectErrorStream = redirectErrorStream;
this.environment = map();
}
protected ProcessExecutor(String[] commandLine, boolean redirectErrorStream) {
this.commandLine = commandLine;
this.redirectErrorStream = redirectErrorStream;
this.environment = map();
}
protected ProcessExecutor(String command, String options, boolean redirectErrorStream) {
this.commandLine = mkCommandLine(command, options);
this.redirectErrorStream = redirectErrorStream;
this.environment = map();
}
private static String[] mkCommandLine(String command, String options) {
final List commandLineList = new ArrayList();
commandLineList.add(command);
Collections.addAll(commandLineList, options.split("\\s+"));
return commandLineList.toArray(new String[commandLineList.size()]);
}
// --
public final void execute() throws ProcessExcecutorException {
Process process = null;
StreamHelper errorStreamHelper = null;
StreamHelper inputStreamHelper = null;
try {
// no special working directory is set which means the working directory of the
// current java process is used.
final ProcessBuilder pbuilder = new ProcessBuilder(commandLine);
pbuilder.redirectErrorStream(redirectErrorStream);
pbuilder.environment().putAll(environment);
process = pbuilder.start();
// consume stdin (the process's stdout)
// Quoting the java doc for {@link Process}:
// "Because some native platforms only provide limited buffer size for standard input and output streams,
// failure to promptly write the input stream or read the output stream of the subprocess may cause the
// subprocess to block, and even deadlock."
// Since it's more likely that a process writes massive amounts to stdout it should be made
// sure to read from it as fast as possible.
// todo use a thread pool to avoid the delay of starting a new thread. Reading late from a
// process's stream is a serious issue which can cause the application to crash or hang.
inputStreamHelper = new StreamHelper(process.getInputStream()) {
@Override protected void append(String output) {
onStdout(output);
}
};
// consume stderr if it is not redirected and merged into stdin
if (!redirectErrorStream) {
errorStreamHelper = new StreamHelper(process.getErrorStream()) {
@Override protected void append(String output) {
onStderr(output);
}
};
}
// wait until streams have been emptied otherwise relevant information may get lost
inputStreamHelper.join();
if (errorStreamHelper != null) {
errorStreamHelper.join();
}
// wait for the process to exit
process.waitFor();
int exitCode = process.exitValue();
// allow subclasses to react to the process result
onProcessFinished(exitCode);
} catch (Throwable t) {
String msg = null;
if (errorStreamHelper != null && errorStreamHelper.contentBuffer != null) {
msg = errorStreamHelper.contentBuffer.toString();
}
// TODO: What if the error stream has been redirected? Can we still get the error messgae?
throw new ProcessExcecutorException(msg, t);
} finally {
IoSupport.closeQuietly(process);
}
}
/**
* A line of output has been read from the processe's stderr. Subclasses should override this method in order to deal
* with process output.
*
* @param line
* the line from stderr
*/
protected void onStderr(String line) {
logger.warn(line);
}
/**
* A line of output has been read from the processe's stdout. Subclasses should override this method in order to deal
* with process output.
*
* @param line
* the line from stdout
*/
protected void onStdout(String line) {
logger.debug(line);
}
protected void onProcessFinished(int exitCode) throws T {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy