Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.robovm.compiler.util;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteResultHandler;
import org.apache.commons.exec.ExecuteStreamHandler;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.ProcessDestroyer;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.exec.launcher.CommandLauncher;
import org.apache.commons.exec.launcher.CommandLauncherFactory;
/**
* The default class to start a subprocess. The implementation
* allows to
*
*
set a current working directory for the subprocess
*
provide a set of environment variables passed to the subprocess
*
capture the subprocess output of stdout and stderr using an ExecuteStreamHandler
*
kill long-running processes using an ExecuteWatchdog
*
define a set of expected exit values
*
terminate any started processes when the main process is terminating using a ProcessDestroyer
*
*
* The following example shows the basic usage:
*
*
* Executor exec = new DefaultExecutor();
* CommandLine cl = new CommandLine("ls -l");
* int exitvalue = exec.execute(cl);
*
*/
class AsyncExecutor implements Executor {
private static final AtomicInteger threadCounter = new AtomicInteger();
/** taking care of output and error stream */
private ExecuteStreamHandler streamHandler;
/** the working directory of the process */
private File workingDirectory;
/** monitoring of long running processes */
private ExecuteWatchdog watchdog;
/** the exit values considerd to be successful */
private int[] exitValues;
/** launches the command in a new process */
private final CommandLauncher launcher;
/** optional cleanup of started processes */
private ProcessDestroyer processDestroyer;
/**
* Default Constrctor
*/
public AsyncExecutor() {
this.streamHandler = new PumpStreamHandler();
this.launcher = CommandLauncherFactory.createVMLauncher();
this.exitValues = new int[0];
}
/**
* Get the StreamHandler used for providing input and
* retriving the output.
*
* @return the StreamHandler
*/
public ExecuteStreamHandler getStreamHandler() {
return streamHandler;
}
/**
* Set the StreamHandler used for providing input and
* retriving the output.
*
* @param streamHandler the StreamHandler
*/
public void setStreamHandler(ExecuteStreamHandler streamHandler) {
this.streamHandler = streamHandler;
}
/**
* Get the watchdog used to kill of processes running,
* typically, too long time.
*
* @return the watchdog
*/
public ExecuteWatchdog getWatchdog() {
return watchdog;
}
/**
* Set the watchdog used to kill of processes running,
* typically, too long time.
*
* @param watchDog the watchdog
*/
public void setWatchdog(ExecuteWatchdog watchDog) {
this.watchdog = watchDog;
}
/**
* Set the handler for cleanup of started processes if the main process
* is going to terminate.
*
* @return the ProcessDestroyer
*/
public ProcessDestroyer getProcessDestroyer() {
return this.processDestroyer;
}
/**
* Get the handler for cleanup of started processes if the main process
* is going to terminate.
*
* @param processDestroyer the ProcessDestroyer
*/
public void setProcessDestroyer(ProcessDestroyer processDestroyer) {
this.processDestroyer = processDestroyer;
}
/**
* Get the working directory of the created process.
*
* @return the working directory
*/
public File getWorkingDirectory() {
return workingDirectory;
}
/**
* Set the working directory of the created process. The
* working directory must exist when you start the process.
*
* @param dir the working directory
*/
public void setWorkingDirectory(File dir) {
this.workingDirectory = dir;
}
/**
* Methods for starting asynchronous execution. The child process inherits
* all environment variables of the parent process.
*
* @param command the command to execute
* @return the launched {@link Process}
* @throws ExecuteException execution of subprocess failed
*/
public Process executeAsync(final CommandLine command) throws IOException {
return executeAsync(command, (Map) null);
}
/**
* Methods for starting asynchronous execution.
*
* @param command the command to execute
* @param environment The environment for the new process. If null, the
* environment of the current process is used.
* @return the launched {@link Process}
* @throws ExecuteException execution of subprocess failed
*/
public Process executeAsync(final CommandLine command, Map environment)
throws IOException {
if (workingDirectory != null && !workingDirectory.exists()) {
throw new IOException(workingDirectory + " doesn't exist.");
}
return executeInternal(command, environment, workingDirectory, streamHandler, null);
}
/**
* Methods for starting asynchronous execution. The child process inherits
* all environment variables of the parent process. Result provided to
* callback handler.
*
* @param command the command to execute
* @param handler capture process termination and exit code
* @return the launched {@link Process}
* @throws ExecuteException execution of subprocess failed
*/
public Process executeAsync(final CommandLine command, ExecuteResultHandler handler)
throws IOException {
return executeAsync(command, null, handler);
}
/**
* Methods for starting asynchronous execution. The child process inherits
* all environment variables of the parent process. Result provided to
* callback handler.
*
* @param command the command to execute
* @param environment The environment for the new process. If null, the
* environment of the current process is used.
* @param handler capture process termination and exit code
* @return the launched {@link Process}
* @throws ExecuteException execution of subprocess failed
*/
public Process executeAsync(final CommandLine command, final Map environment,
final ExecuteResultHandler handler) throws IOException {
if (workingDirectory != null && !workingDirectory.exists()) {
throw new IOException(workingDirectory + " doesn't exist.");
}
return executeInternal(command, environment, workingDirectory, streamHandler, handler);
}
/**
* Define the exit code of the process to considered
* successful.
*
* @param value the exit code representing successful execution
*/
public void setExitValue(final int value) {
this.setExitValues(new int[] {value});
}
/**
* Define the exit code of the process to considered
* successful. The caller can pass one of the following values
*
*
an array of exit values to be considered successful
*
an empty array for auto-detect of successful exit codes
*
null to indicate to skip checking of exit codes
*
*
* @param values a list of the exit codes
*/
public void setExitValues(final int[] values) {
this.exitValues = (values == null ? null : (int[]) values.clone());
}
/**
* Checks whether exitValue signals a failure. If no
* exit values are set than the default conventions of the OS is
* used. e.g. most OS regard an exit code of '0' as successful
* execution and everything else as failure.
*
* @param exitValue the exit value (return code) to be checked
* @return true if exitValue signals a failure
*/
public boolean isFailure(final int exitValue) {
if(this.exitValues == null) {
return false;
}
else if(this.exitValues.length == 0) {
return this.launcher.isFailure(exitValue);
}
else {
for(int i=0; i env,
final File dir) throws IOException {
if (this.launcher == null) {
throw new IllegalStateException("CommandLauncher can not be null");
}
if (dir != null && !dir.exists()) {
throw new IOException(dir + " doesn't exist.");
}
return this.launcher.exec(command, env, dir);
}
/**
* Close the streams belonging to the given Process. In the
* original implementation all exceptions were dropped which
* is probably not a good thing. On the other hand the signature
* allows throwing an IOException so the curent implementation
* might be quite okay.
*
* @param process the Process.
* @throws IOException closing one of the three streams failed
*/
private void closeStreams(final Process process) throws IOException {
IOException caught = null;
try {
process.getInputStream().close();
}
catch(IOException e) {
caught = e;
}
try {
process.getOutputStream().close();
}
catch(IOException e) {
caught = e;
}
try {
process.getErrorStream().close();
}
catch(IOException e) {
caught = e;
}
if(caught != null) {
throw caught;
}
}
/**
* Execute an internal process.
*
* @param command the command to execute
* @param environment the execution enviroment
* @param dir the working directory
* @param streams process the streams (in, out, err) of the process
* @return the launched {@link Process}
* @throws IOException executing the process failed
*/
private Process executeInternal(final CommandLine command, final Map environment,
final File dir, final ExecuteStreamHandler streams,
final ExecuteResultHandler handler) throws IOException {
final Process process = this.launch(command, environment, dir);
try {
streams.setProcessInputStream(process.getOutputStream());
streams.setProcessOutputStream(process.getInputStream());
streams.setProcessErrorStream(process.getErrorStream());
} catch (IOException e) {
process.destroy();
throw e;
}
streams.start();
// add the process to the list of those to destroy if the VM exits
if(this.getProcessDestroyer() != null) {
this.getProcessDestroyer().add(process);
}
if (watchdog != null) {
watchdog.start(process);
}
Thread waitForThread = new Thread(AsyncExecutor.class.getSimpleName()
+ ".waitFor-" + threadCounter.incrementAndGet()) {
public void run() {
int exitValue = Executor.INVALID_EXITVALUE;
try {
try {
exitValue = process.waitFor();
} catch (InterruptedException e) {
process.destroy();
}
if (watchdog != null) {
watchdog.stop();
}
streams.stop();
closeStreams(process);
if (watchdog != null) {
try {
watchdog.checkException();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
if (handler != null) {
handler.onProcessComplete(exitValue);
}
} catch (ExecuteException e) {
if (handler != null) {
handler.onProcessFailed(e);
}
} catch(Exception e) {
if (handler != null) {
handler.onProcessFailed(new ExecuteException("Execution failed", exitValue, e));
}
} finally {
// remove the process to the list of those to destroy if the VM exits
if(AsyncExecutor.this.getProcessDestroyer() != null) {
AsyncExecutor.this.getProcessDestroyer().remove(process);
}
}
}
};
waitForThread.setDaemon(true);
waitForThread.start();
return process;
}
@Override
public int execute(CommandLine command) throws ExecuteException,
IOException {
throw new UnsupportedOperationException();
}
@Override
public int execute(CommandLine command, Map environment)
throws ExecuteException, IOException {
throw new UnsupportedOperationException();
}
@Override
public void execute(CommandLine command, ExecuteResultHandler handler)
throws ExecuteException, IOException {
throw new UnsupportedOperationException();
}
@Override
public void execute(CommandLine command, Map environment,
ExecuteResultHandler handler) throws ExecuteException, IOException {
throw new UnsupportedOperationException();
}
}