// Path: src/main/java/org/apache/commons/exec/launcher/CommandLauncher.java
// public interface CommandLauncher {
// 
//     /**
//      * Launches the given command in a new process.
//      *
//      * @param cmd
//      *            The command to execute
//      * @param env
//      *            The environment for the new process. If null, the environment
//      *            of the current process is used.
//      *
//      * @return the newly created process
//      * @throws IOException
//      *             if attempting to run a command in a specific directory
//      */
//     Process exec(final CommandLine cmd, final Map<String, String> env)
//             throws IOException;
// 
//     /**
//      * Launches the given command in a new process, in the given working
//      * directory.
//      *
//      * @param cmd
//      *            The command to execute
//      * @param env
//      *            The environment for the new process. If null, the environment
//      *            of the current process is used.
//      * @param workingDir
//      *            The directory to start the command in. If null, the current
//      *            directory is used
//      *
//      * @return the newly created process
//      * @throws IOException
//      *             if trying to change directory
//      */
//     Process exec(final CommandLine cmd, final Map<String, String> env,
//             final File workingDir) throws IOException;
// 
// 
//     /**
//      * Checks whether {@code exitValue} signals a failure on the current
//      * system (OS specific).
//      * <p>
//      * <b>Note</b> that this method relies on the conventions of the OS, it
//      * will return false results if the application you are running doesn't
//      * follow these conventions. One notable exception is the Java VM provided
//      * by HP for OpenVMS - it will return 0 if successful (like on any other
//      * platform), but this signals a failure on OpenVMS. So if you execute a new
//      * Java VM on OpenVMS, you cannot trust this method.
//      * </p>
//      *
//      * @param exitValue the exit value (return code) to be checked
//      * @return {@code true} if {@code exitValue} signals a failure
//      */
//     boolean isFailure(final int exitValue);
// }
// 
// Path: src/main/java/org/apache/commons/exec/launcher/CommandLauncherFactory.java
// public final class CommandLauncherFactory {
// 
//     private CommandLauncherFactory() {
//     }
// 
//     /**
//      * Factory method to create an appropriate launcher.
//      *
//      * @return the command launcher
//      */
//     public static CommandLauncher createVMLauncher() {
//         // Try using a JDK 1.3 launcher
//         CommandLauncher launcher;
// 
//         if (OS.isFamilyOpenVms()) {
//             launcher = new VmsCommandLauncher();
//         } else {
//             launcher = new Java13CommandLauncher();
//         }
// 
//         return launcher;
//     }
// }


import org.apache.commons.exec.launcher.CommandLauncher;
import org.apache.commons.exec.launcher.CommandLauncherFactory;
import java.io.File;
import java.io.IOException;
import java.util.Map;
/*
 * 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.commons.exec;



/**
 * The default class to start a subprocess. The implementation
 * allows to
 * <ul>
 *  <li>set a current working directory for the subprocess</li>
 *  <li>provide a set of environment variables passed to the subprocess</li>
 *  <li>capture the subprocess output of stdout and stderr using an ExecuteStreamHandler</li>
 *  <li>kill long-running processes using an ExecuteWatchdog</li>
 *  <li>define a set of expected exit values</li>
 *  <li>terminate any started processes when the main process is terminating using a ProcessDestroyer</li>
 * </ul>
 *
 * The following example shows the basic usage:
 *
 * <pre>
 * Executor exec = new DefaultExecutor();
 * CommandLine cl = new CommandLine("ls -l");
 * int exitvalue = exec.execute(cl);
 * </pre>
 *
 */
public class DefaultExecutor implements Executor {

    /** 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 considered 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;

    /** worker thread for asynchronous execution */
    private Thread executorThread;

    /** the first exception being caught to be thrown to the caller */
    private IOException exceptionCaught;

    /**
     * Default constructor creating a default {@code PumpStreamHandler}
     * and sets the working directory of the subprocess to the current
     * working directory.
     *
     * The {@code PumpStreamHandler} pumps the output of the subprocess
     * into our {@code System.out} and {@code System.err} to avoid
     * into our {@code System.out} and {@code System.err} to avoid
     * a blocked or deadlocked subprocess (see{@link java.lang.Process Process}).
     */
    public DefaultExecutor() {
        this.streamHandler = new PumpStreamHandler();
        this.launcher = CommandLauncherFactory.createVMLauncher();
        this.exitValues = new int[0];
        this.workingDirectory = new File(".");
        this.exceptionCaught = null;
    }

    /**
     * @see org.apache.commons.exec.Executor#getStreamHandler()
     */
    @Override
    public ExecuteStreamHandler getStreamHandler() {
        return streamHandler;
    }

    /**
     * @see org.apache.commons.exec.Executor#setStreamHandler(org.apache.commons.exec.ExecuteStreamHandler)
     */
    @Override
    public void setStreamHandler(final ExecuteStreamHandler streamHandler) {
        this.streamHandler = streamHandler;
    }

    /**
     * @see org.apache.commons.exec.Executor#getWatchdog()
     */
    @Override
    public ExecuteWatchdog getWatchdog() {
        return watchdog;
    }

    /**
     * @see org.apache.commons.exec.Executor#setWatchdog(org.apache.commons.exec.ExecuteWatchdog)
     */
// Path: src/main/java/org/apache/commons/exec/launcher/CommandLauncher.java
// public interface CommandLauncher {
// 
//     /**
//      * Launches the given command in a new process.
//      *
//      * @param cmd
//      *            The command to execute
//      * @param env
//      *            The environment for the new process. If null, the environment
//      *            of the current process is used.
//      *
//      * @return the newly created process
//      * @throws IOException
//      *             if attempting to run a command in a specific directory
//      */
//     Process exec(final CommandLine cmd, final Map<String, String> env)
//             throws IOException;
// 
//     /**
//      * Launches the given command in a new process, in the given working
//      * directory.
//      *
//      * @param cmd
//      *            The command to execute
//      * @param env
//      *            The environment for the new process. If null, the environment
//      *            of the current process is used.
//      * @param workingDir
//      *            The directory to start the command in. If null, the current
//      *            directory is used
//      *
//      * @return the newly created process
//      * @throws IOException
//      *             if trying to change directory
//      */
//     Process exec(final CommandLine cmd, final Map<String, String> env,
//             final File workingDir) throws IOException;
// 
// 
//     /**
//      * Checks whether {@code exitValue} signals a failure on the current
//      * system (OS specific).
//      * <p>
//      * <b>Note</b> that this method relies on the conventions of the OS, it
//      * will return false results if the application you are running doesn't
//      * follow these conventions. One notable exception is the Java VM provided
//      * by HP for OpenVMS - it will return 0 if successful (like on any other
//      * platform), but this signals a failure on OpenVMS. So if you execute a new
//      * Java VM on OpenVMS, you cannot trust this method.
//      * </p>
//      *
//      * @param exitValue the exit value (return code) to be checked
//      * @return {@code true} if {@code exitValue} signals a failure
//      */
//     boolean isFailure(final int exitValue);
// }
// 
// Path: src/main/java/org/apache/commons/exec/launcher/CommandLauncherFactory.java
// public final class CommandLauncherFactory {
// 
//     private CommandLauncherFactory() {
//     }
// 
//     /**
//      * Factory method to create an appropriate launcher.
//      *
//      * @return the command launcher
//      */
//     public static CommandLauncher createVMLauncher() {
//         // Try using a JDK 1.3 launcher
//         CommandLauncher launcher;
// 
//         if (OS.isFamilyOpenVms()) {
//             launcher = new VmsCommandLauncher();
//         } else {
//             launcher = new Java13CommandLauncher();
//         }
// 
//         return launcher;
//     }
// }


// Path: src/main/java/org/apache/commons/exec/DefaultExecutor.java
import org.apache.commons.exec.launcher.CommandLauncher;
import org.apache.commons.exec.launcher.CommandLauncherFactory;
import java.io.File;
import java.io.IOException;
import java.util.Map;

/*
 * 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.commons.exec;



/**
 * The default class to start a subprocess. The implementation
 * allows to
 * <ul>
 *  <li>set a current working directory for the subprocess</li>
 *  <li>provide a set of environment variables passed to the subprocess</li>
 *  <li>capture the subprocess output of stdout and stderr using an ExecuteStreamHandler</li>
 *  <li>kill long-running processes using an ExecuteWatchdog</li>
 *  <li>define a set of expected exit values</li>
 *  <li>terminate any started processes when the main process is terminating using a ProcessDestroyer</li>
 * </ul>
 *
 * The following example shows the basic usage:
 *
 * <pre>
 * Executor exec = new DefaultExecutor();
 * CommandLine cl = new CommandLine("ls -l");
 * int exitvalue = exec.execute(cl);
 * </pre>
 *
 */
public class DefaultExecutor implements Executor {

    /** 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 considered 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;

    /** worker thread for asynchronous execution */
    private Thread executorThread;

    /** the first exception being caught to be thrown to the caller */
    private IOException exceptionCaught;

    /**
     * Default constructor creating a default {@code PumpStreamHandler}
     * and sets the working directory of the subprocess to the current
     * working directory.
     *
     * The {@code PumpStreamHandler} pumps the output of the subprocess
     * into our {@code System.out} and {@code System.err} to avoid
     * into our {@code System.out} and {@code System.err} to avoid
     * a blocked or deadlocked subprocess (see{@link java.lang.Process Process}).
     */
    public DefaultExecutor() {
        this.streamHandler = new PumpStreamHandler();
        this.launcher = CommandLauncherFactory.createVMLauncher();
        this.exitValues = new int[0];
        this.workingDirectory = new File(".");
        this.exceptionCaught = null;
    }

    /**
     * @see org.apache.commons.exec.Executor#getStreamHandler()
     */
    @Override
    public ExecuteStreamHandler getStreamHandler() {
        return streamHandler;
    }

    /**
     * @see org.apache.commons.exec.Executor#setStreamHandler(org.apache.commons.exec.ExecuteStreamHandler)
     */
    @Override
    public void setStreamHandler(final ExecuteStreamHandler streamHandler) {
        this.streamHandler = streamHandler;
    }

    /**
     * @see org.apache.commons.exec.Executor#getWatchdog()
     */
    @Override
    public ExecuteWatchdog getWatchdog() {
        return watchdog;
    }

    /**
     * @see org.apache.commons.exec.Executor#setWatchdog(org.apache.commons.exec.ExecuteWatchdog)
     */
    @Override