blob: ad99ef655990f4f94288cee7104ee82235215a6a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache 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://www.apache.org/licenses/LICENSE-2.0
*
* 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.apache.openmeetings.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.apache.openmeetings.OpenmeetingsVariables;
import org.apache.openmeetings.documents.beans.ConverterProcessResult;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;
public class ProcessHelper {
public static final Logger log = Red5LoggerFactory.getLogger(ProcessHelper.class, OpenmeetingsVariables.webAppRootKey);
private static class Worker extends Thread {
private final Process process;
private Integer exitCode;
private Worker(Process process) {
this.process = process;
}
@Override
public void run() {
try {
exitCode = process.waitFor();
} catch (InterruptedException ignore) {
return;
}
}
}
private static class StreamWatcher extends Thread {
public StringBuilder output;
private final InputStream is;
private final BufferedReader br;
private StreamWatcher(Process process, boolean isError) throws UnsupportedEncodingException {
output = new StringBuilder();
is = isError ? process.getErrorStream() : process.getInputStream();
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
}
@Override
public void run() {
try {
String line = br.readLine();
while (line != null) {
output.append(line).append('\n');
line = br.readLine();
}
} catch (IOException ioexception) {
log.error("[run]", ioexception);
return;
}
}
}
public static ConverterProcessResult executeScriptWindows(String process, String[] argv) {
try {
String[] cmd = new String[argv.length + 2];
cmd[0] = "cmd.exe";
cmd[1] = "/C";
System.arraycopy(argv, 0, cmd, 2, argv.length);
Map<String, String> env = new HashMap<String, String>();
return executeScript(process, cmd, env);
} catch (Exception t) {
log.error("executeScriptWindows", t);
return new ConverterProcessResult(process, t.getMessage(), t);
}
}
public static ConverterProcessResult executeScript(String process, String[] argv) {
Map<String, String> env = new HashMap<String, String>();
return executeScript(process, argv, env);
}
public static ConverterProcessResult executeScript(String process,
String[] argv, Map<? extends String, ? extends String> env) {
ConverterProcessResult returnMap = new ConverterProcessResult();
returnMap.setProcess(process);
log.debug("process: " + process);
log.debug("args: " + Arrays.toString(argv));
try {
returnMap.setCommand(Arrays.toString(argv));
returnMap.setOut("");
// By using the process Builder we have access to modify the
// environment variables
// that is handy to set variables to run it inside eclipse
ProcessBuilder pb = new ProcessBuilder(argv);
pb.environment().putAll(env);
Process proc = pb.start();
// 20-minute timeout for command execution
// FFMPEG conversion of Recordings may take a real long time until
// its finished
long timeout = 60000 * 20;
StreamWatcher errorWatcher = new StreamWatcher(proc, true);
Worker worker = new Worker(proc);
StreamWatcher inputWatcher = new StreamWatcher(proc, false);
errorWatcher.start();
inputWatcher.start();
worker.start();
try {
worker.join(timeout);
if (worker.exitCode != null) {
returnMap.setExitValue(""+worker.exitCode);
log.debug("exitVal: " + worker.exitCode);
returnMap.setError(errorWatcher.output.toString());
} else {
returnMap.setException("timeOut");
returnMap.setError(errorWatcher.output.toString());
returnMap.setExitValue("-1");
throw new TimeoutException();
}
} catch (InterruptedException ex) {
worker.interrupt();
errorWatcher.interrupt();
inputWatcher.interrupt();
Thread.currentThread().interrupt();
returnMap.setError(ex.getMessage());
returnMap.setExitValue("-1");
throw ex;
} finally {
proc.destroy();
}
} catch (TimeoutException e) {
// Timeout exception is processed above
log.error("executeScript",e);
returnMap.setError(e.getMessage());
returnMap.setException(e.toString());
returnMap.setExitValue("-1");
} catch (Throwable t) {
// Any other exception is shown in debug window
log.error("executeScript",t);
returnMap.setError(t.getMessage());
returnMap.setException(t.toString());
returnMap.setExitValue("-1");
}
return returnMap;
}
}