All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.io.ProcessLauncher Maven / Gradle / Ivy

/*
 * File:                ProcessLauncher.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Framework Lite
 *
 * Copyright September 20, 2006, Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
 * or on behalf of the U.S. Government. Export of this program may require a
 * license from the United States Government. See CopyrightHistory.txt for
 * complete details.
 *
 *
 */

package gov.sandia.cognition.io;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Launches a process as a separate thread and monitors the stdout and stderr,
 * throwing events when they update and exit
 *
 * @author Kevin R. Dixon
 * @since  1.0
 *
 */
public class ProcessLauncher
    extends Thread
{

    /**
     * Actual command line passed to the Runtime.exec() command
     */
    private String actualCommand;

    /**
     * Internal process that is spawned from the command
     */
    private Process process;

    /**
     * Listeners that are interested in the events fired by this object
     */
    private LinkedList listeners;

    /**
     * Thread that consumes stdout
     */
    private StreamGobbler stdout;

    /**
     * Thread that consumes stderr
     */
    private StreamGobbler stderr;

    /**
     * Thread class that asynchronously process the outputs from the process,
     * and throws events when a new line is encountered
     */
    private class StreamGobbler extends Thread
    {

        /**
         * Stream to monitor
         */
        InputStream stream;

        /**
         * Type of events to fire
         */
        ProcessLauncherEvent.EventType type;

        /**
         * Creates a new instance of StreamGobbler
         * @param stream 
         * Stream to monitor
         * @param type 
         * Type of events to fire
         */
        StreamGobbler(
            InputStream stream,
            ProcessLauncherEvent.EventType type )
        {
            this.stream = stream;
            this.type = type;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void run()
        {

            BufferedReader stdInput = new BufferedReader(
                new InputStreamReader( this.stream ) );

            try
            {
                String line;
                while ((line = stdInput.readLine()) != null)
                {
                    ProcessLauncher.this.fireEvent(
                        new ProcessLauncherEvent( this.type, line, null ) );
                }
            }
            catch (Exception e)
            {
                throw new RuntimeException( e );
            }


        }

    }

    /**
     * Creates a new instance of ProcessLauncher
     * @param command
     * String command, and all its arguments, to launch
     */
    public ProcessLauncher(
        String command )
    {

        String osName = System.getProperty( "os.name" );
        if (osName.equals( "Windows XP" ))
        {
            this.setActualCommand( "cmd.exe /C \"" + command + "\"" );
        }
        else
        {
            this.setActualCommand( command );
        }

        this.setProcess( null );
        this.stdout = null;
        this.stderr = null;
        this.listeners = new LinkedList();

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void run()
    {

        try
        {
            Logger.getLogger(ProcessLauncher.class.getName()).info("Executing: " + this.getActualCommand());
            this.setProcess( Runtime.getRuntime().exec( this.getActualCommand() ) );

            this.stdout = new StreamGobbler(
                this.getProcess().getInputStream(), ProcessLauncherEvent.EventType.STDOUT );
            this.stdout.start();

            this.stderr = new StreamGobbler(
                this.getProcess().getErrorStream(), ProcessLauncherEvent.EventType.STDERR );
            this.stderr.start();

            this.getProcess().waitFor();

            this.fireEvent( new ProcessLauncherEvent(
                ProcessLauncherEvent.EventType.FINISHED, null, this.getProcess() ) );
        }
        catch (Exception e)
        {
            throw new RuntimeException( e );
        }

    }

    /**
     * Adds the listener to the event queue
     * @param listener 
     * Object that wishes to receive update events
     */
    public void addListener(
        ProcessLauncherListener listener )
    {
        this.listeners.add( listener );
    }

    /**
     * Removes the given object from the event queue
     * @param listener 
     * Object that no longer wants to receive update events
     */
    public void removeListener(
        ProcessLauncherListener listener )
    {
        this.listeners.remove( listener );
    }

    /**
     * Passes the event to all the subscribed listeners
     * @param event 
     */
    private void fireEvent(
        ProcessLauncherEvent event )
    {
        for (ProcessLauncherListener listener : this.listeners)
        {
            listener.processLauncherEvent( event );
        }
    }

    /**
     * Stops the process.  The does not work on Windows, as we have to
     * envelope the desired command using "cmd.exe /c".  So the stop process
     * call actually cancels cmd.exe, and happily lets the desired command
     * continue running
     */
    public void stopProcess()
    {
        if (this.getProcess() != null)
        {
            this.getProcess().destroy();
            this.setProcess( null );
        }

        if (this.stdout != null)
        {
            this.stdout.interrupt();
            this.stdout = null;
        }

        if (this.stderr != null)
        {
            this.stderr.interrupt();
            this.stdout = null;
        }

        this.interrupt();

    }

    /**
     * Getter for process
     * @return 
     * Internal process that is spawned from the command
     */
    public Process getProcess()
    {
        return this.process;
    }

    /**
     * Setter for process
     * @param process 
     * Internal process that is spawned from the command
     */
    protected void setProcess(
        Process process )
    {
        this.process = process;
    }

    /**
     * Getter for actualCommand
     * @return 
     * Actual command line passed to the Runtime.exec() command
     */
    public String getActualCommand()
    {
        return this.actualCommand;
    }

    /**
     * Setter for actualCommand
     * @param actualCommand 
     * Actual command line passed to the Runtime.exec() command
     */
    protected void setActualCommand(
        String actualCommand )
    {
        this.actualCommand = actualCommand;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy