ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dona...@apache.org
Subject cvs commit: jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/exec Execute.java
Date Sun, 30 Dec 2001 06:49:51 GMT
donaldp     01/12/29 22:49:51

  Modified:    proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/exec
                        Execute.java
  Added:       proposal/myrmidon/src/java/org/apache/myrmidon/framework/exec/impl
                        DefaultExecManager.java ProcessDestroyer.java
                        ProcessMonitor.java
  Removed:     proposal/myrmidon/src/java/org/apache/myrmidon/framework/exec
                        DefaultExecManager.java ProcessDestroyer.java
                        ProcessMonitor.java
  Log:
  Moved implementation of ExecManager into new package
  
  Revision  Changes    Path
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/framework/exec/impl/DefaultExecManager.java
  
  Index: DefaultExecManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.framework.exec.impl;
  
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Locale;
  import org.apache.avalon.excalibur.io.FileUtil;
  import org.apache.myrmidon.framework.Os;
  import org.apache.myrmidon.framework.exec.CommandLauncher;
  import org.apache.myrmidon.framework.exec.ExecException;
  import org.apache.myrmidon.framework.exec.ExecManager;
  import org.apache.myrmidon.framework.exec.ExecMetaData;
  import org.apache.myrmidon.framework.exec.launchers.DefaultCommandLauncher;
  import org.apache.myrmidon.framework.exec.launchers.MacCommandLauncher;
  import org.apache.myrmidon.framework.exec.launchers.ScriptCommandLauncher;
  import org.apache.myrmidon.framework.exec.launchers.WinNTCommandLauncher;
  
  /**
   * Default implementation of <code>ExecManager</code>.
   * Used to run processes in the ant environment.
   *
   * @author <a href="mailto:peter@apache.org">Peter Donald</a>
   * @author <a href="mailto:thomas.haas@softwired-inc.com">Thomas Haas</a>
   * @version $Revision: 1.1 $ $Date: 2001/12/30 06:49:51 $
   * @see ExecManager
   * @see ExecMetaData
   */
  public class DefaultExecManager
      implements ExecManager
  {
      /**
       * Used to destroy processes when the VM exits.
       */
      private final ProcessDestroyer m_processDestroyer = new ProcessDestroyer();
  
      private final CommandLauncher m_launcher;
      private final CommandLauncher m_shellLauncher;
  
      public DefaultExecManager( final File antDir )
          throws ExecException
      {
          m_launcher = new DefaultCommandLauncher();
          m_shellLauncher = createShellLauncher( antDir );
      }
  
      /**
       * Execute a process and wait for it to finish before
       * returning.
       */
      public int execute( final ExecMetaData metaData,
                          final InputStream input,
                          final OutputStream output,
                          final OutputStream error,
                          final long timeout )
          throws IOException, ExecException
      {
          final CommandLauncher launcher = getLauncher( metaData );
          final Process process = launcher.exec( metaData );
          final ProcessMonitor monitor =
              new ProcessMonitor( process, input, output, error, timeout );
  
          final Thread thread = new Thread( monitor, "ProcessMonitor" );
          thread.start();
  
          // add the process to the list of those to destroy if the VM exits
          m_processDestroyer.add( process );
  
          waitFor( process );
  
          //Now wait for monitor to finish aswell
          try
          {
              thread.join();
          }
          catch( InterruptedException e )
          {
              //should never occur.
          }
  
          // remove the process to the list of those to destroy if the VM exits
          m_processDestroyer.remove( process );
  
          if( monitor.didProcessTimeout() )
          {
              throw new ExecException( "Process Timed out" );
          }
  
          return process.exitValue();
      }
  
      private void waitFor( final Process process )
      {
          //Should loop around until process is terminated.
          try
          {
              process.waitFor();
          }
          catch( final InterruptedException ie )
          {
              //should never happen
          }
      }
  
      private CommandLauncher getLauncher( final ExecMetaData metaData )
      {
          CommandLauncher launcher = m_launcher;
          if( false ) //!m_useVMLauncher )
          {
              launcher = m_shellLauncher;
          }
          return launcher;
      }
  
      private CommandLauncher createShellLauncher( final File antDir )
          throws ExecException
      {
          CommandLauncher launcher = null;
  
          if( Os.isFamily( "mac" ) )
          {
              // Mac
              launcher = new MacCommandLauncher();
          }
          else if( Os.isFamily( "os/2" ) )
          {
              // OS/2 - use same mechanism as Windows 2000
              launcher = new WinNTCommandLauncher();
          }
          else if( Os.isFamily( "windows" ) )
          {
              // Windows.  Need to determine which JDK we're running in
  
              // Determine if we're running under 2000/NT or 98/95
              final String osname =
                  System.getProperty( "os.name" ).toLowerCase( Locale.US );
  
              if( osname.indexOf( "nt" ) >= 0 || osname.indexOf( "2000" ) >= 0 )
              {
                  // Windows 2000/NT
                  launcher = new WinNTCommandLauncher();
              }
              else
              {
                  // Windows 98/95 - need to use an auxiliary script
                  final String script = resolveCommand( antDir, "bin/antRun.bat" );
                  launcher = new ScriptCommandLauncher( script );
              }
          }
          else if( ( new Os( "netware" ) ).eval() )
          {
              // NetWare.  Need to determine which JDK we're running in
              final String perlScript = resolveCommand( antDir, "bin/antRun.pl" );
              final String[] script = new String[]{"perl", perlScript};
              launcher = new ScriptCommandLauncher( script );
          }
          else
          {
              // Generic
              final String script = resolveCommand( antDir, "bin/antRun" );
              launcher = new ScriptCommandLauncher( script );
          }
  
          return launcher;
      }
  
      private String resolveCommand( final File antDir, final String command )
      {
          return FileUtil.resolveFile( antDir, command ).toString();
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/framework/exec/impl/ProcessDestroyer.java
  
  Index: ProcessDestroyer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.framework.exec.impl;
  
  import java.lang.reflect.Method;
  import java.util.ArrayList;
  import java.util.Iterator;
  
  /**
   * Destroys all registered <code>Process</code>es when
   * the VM exits (if in JDK1.3) or when requested.
   *
   * @author <a href="mailto:mnewcomb@tacintel.com">Michael Newcomb</a>
   * @author <a href="mailto:peter@apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2001/12/30 06:49:51 $
   */
  class ProcessDestroyer
      extends Thread
  {
      private ArrayList m_processes = new ArrayList();
  
      /**
       * Constructs a <code>ProcessDestroyer</code> and registers it as a shutdown
       * hook.
       */
      public ProcessDestroyer()
      {
          try
          {
              // check to see if the method exists (support pre-JDK 1.3 VMs)
              //
              final Class[] paramTypes = {Thread.class};
              final Method addShutdownHook =
                  Runtime.class.getMethod( "addShutdownHook", paramTypes );
  
              // add the hook
              Object[] args = {this};
              addShutdownHook.invoke( Runtime.getRuntime(), args );
          }
          catch( final Exception e )
          {
              // it just won't be added as a shutdown hook... :(
          }
      }
  
      /**
       * Add process to list of processes to be shutdown.
       *
       * @param process the process to add
       */
      public synchronized void add( final Process process )
      {
          if( !m_processes.contains( process ) )
          {
              m_processes.add( process );
          }
      }
  
      /**
       * Remove process from list of processes to be shutdown.
       *
       * @param process the process to remove
       */
      public synchronized void remove( final Process process )
      {
          m_processes.remove( process );
      }
  
      /**
       * Invoked by the VM when it is exiting.
       */
      public void run()
      {
          destroyProcesses();
      }
  
      protected synchronized void destroyProcesses()
      {
          final Iterator processes = m_processes.iterator();
          while( processes.hasNext() )
          {
              ( (Process)processes.next() ).destroy();
              processes.remove();
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/framework/exec/impl/ProcessMonitor.java
  
  Index: ProcessMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.myrmidon.framework.exec.impl;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  
  /**
   * This class is responsible for monitoring a process.
   * It will monitor a process and if it goes longer than its timeout
   * then it will terminate it. The monitor will also read data from
   * stdout and stderr of process and pass it onto user specified streams.
   * It will also in the future do the same for stdin.
   *
   * @author <a href="mailto:peter@apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2001/12/30 06:49:51 $
   */
  class ProcessMonitor
      extends AbstractLogEnabled
      implements Runnable
  {
      //Time to sleep in loop while processing output
      //of command and monitoring for timeout
      private final static int SLEEP_TIME = 5;
  
      //State to indicate process is still running
      private static final int STATE_RUNNING = 0;
  
      //State to indicate process shutdown by itself
      private static final int STATE_STOPPED = 1;
  
      //State to indicate process was terminated due to timeout
      private static final int STATE_TERMINATED = 2;
  
      /**
       * The state of the process monitor and thus
       * the state of the underlying process.
       */
      private int m_state = STATE_RUNNING;
  
      /**
       * This is the process we are monitoring.
       */
      private final Process m_process;
  
      /**
       * This specifies the time at which this process will
       * timeout. 0 implies no timeout.
       */
      private final long m_timeout;
  
      /**
       * Stream from which to read standard input.
       */
      private final InputStream m_input;
  
      /**
       * Stream to write standard output to.
       */
      private final OutputStream m_output;
  
      /**
       * Stream to write standard error to.
       */
      private final OutputStream m_error;
  
      public ProcessMonitor( final Process process,
                             final InputStream input,
                             final OutputStream output,
                             final OutputStream error,
                             final long timeoutDuration )
      {
          if( null == process )
          {
              throw new NullPointerException( "process" );
          }
  
          if( 0 > timeoutDuration )
          {
              throw new IllegalArgumentException( "timeoutDuration" );
          }
  
          final long now = System.currentTimeMillis();
          long timeout = 0;
          if( 0 != timeoutDuration )
          {
              timeout = now + timeoutDuration;
          }
  
          m_process = process;
          m_input = input;
          m_output = output;
          m_error = error;
          m_timeout = timeout;
      }
  
      /**
       * Utility method to check if process timed out.
       * Only valid after run() has exited.
       */
      public boolean didProcessTimeout()
      {
          return ( m_state == STATE_TERMINATED );
      }
  
      /**
       * Thread method to monitor the state of the process.
       */
      public void run()
      {
          while( STATE_RUNNING == m_state )
          {
              processStandardInput();
              processStandardOutput();
              processStandardError();
  
              if( !isProcessStopped() )
              {
                  checkTimeout();
              }
  
              try
              {
                  Thread.sleep( SLEEP_TIME );
              }
              catch( final InterruptedException ie )
              {
                  //swallow it
              }
          }
      }
  
      /**
       * Check if process has stopped. If it has then update state
       * and return true, else return false.
       */
      private boolean isProcessStopped()
      {
          boolean stopped;
          try
          {
              m_process.exitValue();
              stopped = true;
          }
          catch( final IllegalThreadStateException itse )
          {
              stopped = false;
          }
  
          if( stopped )
          {
              m_state = STATE_STOPPED;
          }
  
          return stopped;
      }
  
      /**
       * Check if the process has exceeded time allocated to it.
       * If it has reached timeout then terminate the process
       * and set state to <code>STATE_TERMINATED</code>.
       */
      private void checkTimeout()
      {
          if( 0 == m_timeout )
          {
              return;
          }
  
          final long now = System.currentTimeMillis();
          if( now > m_timeout )
          {
              m_state = STATE_TERMINATED;
              m_process.destroy();
          }
      }
  
      /**
       * Process the standard input of process.
       * Reading it from user specified stream and copy it
       * to processes standard input stream.
       */
      private void processStandardInput()
      {
          if( null != m_input )
          {
              //Note can not do this as the process may block
              //when written to which will result in this whole
              //thread being blocked. Probably need to write to
              //stdin in another thread
              //copy( m_input, m_process.getOutputStream() );
          }
      }
  
      /**
       * Process the standard output of process.
       * Reading it and sending it to user specified stream
       * or into the void.
       */
      private void processStandardOutput()
      {
          final InputStream input = m_process.getInputStream();
          copy( input, m_output );
      }
  
      /**
       * Process the standard error of process.
       * Reading it and sending it to user specified stream
       * or into the void.
       */
      private void processStandardError()
      {
          final InputStream input = m_process.getInputStream();
          copy( input, m_error );
      }
  
      /**
       * Copy data from specified input stream to output stream if
       * output stream exists. The size of data that should be attempted
       * to read is determined by calling available() on input stream.
       */
      private void copy( final InputStream input,
                         final OutputStream output )
      {
          try
          {
              final int available = input.available();
              if( 0 >= available ) return;
  
              final byte[] data = new byte[ available ];
              final int read = input.read( data );
  
              if( null != output )
              {
                  output.write( data, 0, read );
              }
          }
          catch( final IOException ioe )
          {
              final String message = "Error processing streams";
              getLogger().error( message, ioe );
          }
      }
  }
  
  
  
  1.22      +1 -1      jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/exec/Execute.java
  
  Index: Execute.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/exec/Execute.java,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- Execute.java	30 Dec 2001 00:02:06 -0000	1.21
  +++ Execute.java	30 Dec 2001 06:49:51 -0000	1.22
  @@ -12,7 +12,7 @@
   import java.io.OutputStream;
   import java.util.Properties;
   import org.apache.myrmidon.api.TaskException;
  -import org.apache.myrmidon.framework.exec.DefaultExecManager;
  +import org.apache.myrmidon.framework.exec.impl.DefaultExecManager;
   import org.apache.myrmidon.framework.exec.ExecException;
   import org.apache.myrmidon.framework.exec.ExecMetaData;
   import org.apache.tools.ant.Project;
  
  
  

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message