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:[EMAIL PROTECTED]">Peter Donald</a>
* @author <a href="mailto:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">Michael Newcomb</a>
* @author <a href="mailto:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>