4/17/2008

How To Safely Execute Process From Java

Filed under: — Aviran Mordo @ 8:20 am

Sometimes your Java application will need to execute an external process which you do not have any control over. Executing external applications from Java is problematic since you do not know when they end, you need to capture their output and parse it and also make sure that they will not hang and causes your program to wait for them forever.

There are several ways you can execute external applications while protecting your program. The following example will show you how to execute a process, get the response as a string and specify a timeout period in which the external application has to finish. In case the process did not finish after the timeout period we’ll abort the process and throw TimeoutException


package com.aviransplace.runtime.util;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeoutException;

/**
* Execute command from the Runtime. This class will make sure the external application will not hung the application by specifying
* a timeout in which the application must return. If it does not an InterruptedException will be thrown
*
* @author Aviran Mordo
*
*/
public class RuntimeExecutor
{
private long timeout = Long.MAX_VALUE;

/**
* Default constructor - Timeout set to Long.MAX_VALUE
*/
public RuntimeExecutor()
{
// Do nothing
}

/**
* Constructor
* @param timeout Set the timeout for the external application to run
*/
public RuntimeExecutor(long timeout)
{
this.timeout = timeout;
}

/**
* Execute a Runtime process
* @param command - The command to execute
* @param env - Environment variables to put in the Runtime process
* @return The output from the process
* @throws IOException
* @throws TimeoutException - Process timed out and did not return in the specified amount of time
*/
public String execute(String command, String[] env) throws IOException, TimeoutException
{
Process p = Runtime.getRuntime().exec(command, env);

// Set a timer to interrupt the process if it does not return within the timeout period
Timer timer = new Timer();
timer.schedule(new InterruptScheduler(Thread.currentThread()), this.timeout);

try
{
p.waitFor();
} catch (InterruptedException e)
{
// Stop the process from running
p.destroy();
throw new TimeoutException(command + "did not return after "+this.timeout+" milliseconds");
}
finally
{
// Stop the timer
timer.cancel();
}

// Get the output from the external application
StringBuilder buffer = new StringBuilder();
BufferedInputStream br = new BufferedInputStream(p.getInputStream());
while (br.available() != 0)
{
buffer.append((char) br.read());
}
String res = buffer.toString().trim();
return res;

}

// ///////////////////////////////////////////
private class InterruptScheduler extends TimerTask
{
Thread target = null;

public InterruptScheduler(Thread target)
{
this.target = target;
}

@Override
public void run()
{
target.interrupt();
}

}

public static void main(String[] args)
{
// Set timeout to 3 seconds
RuntimeExecutor r = new RuntimeExecutor(3000);
try
{
System.out.println(r.execute("grep java", null));
} catch (IOException e)
{
e.printStackTrace();
} catch (TimeoutException e)
{
e.printStackTrace();
}

System.out.println("STOPPED");
}
}

 

One Response to “How To Safely Execute Process From Java”

  1. Miro Says:

    Unfortunately, your program will fail if the executed process writes more then 4096 characters to stdout or stderr. I think java sucks here. The Process class has been stupidly designed. I think the only cure is to spawn a thread for reading the streams while process.waitFor().

Leave a Reply

You must have Javascript enabled in order to submit comments.

All fields are optional (except comment).
Some comments may be held for moderation (depends on spam filter) and not show up immediately.
Links will automatically get rel="nofollow" attribute to deter spammers.

Powered by WordPress