package org.jboss.varia.process;
import java.util.Properties;
import java.util.Iterator;
import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.util.NullArgumentException;
public class ChildProcessService
extends ServiceMBeanSupport
implements ChildProcessServiceMBean
{
protected String commandLine;
protected Properties env;
protected File workingDir;
protected Process childProcess;
protected String loggerAdapterName = this.getClass().getName();
protected ReaderLoggerAdapter inputAdapter;
protected ReaderLoggerAdapter errorAdapter;
public void setCommandLine(final String commandLine)
{
if (commandLine == null)
throw new NullArgumentException("commandLine");
this.commandLine = commandLine;
}
public String getCommandLine()
{
return commandLine;
}
public void setEnvironment(final Properties env)
{
this.env = env;
}
public Properties getEnvironment()
{
return env;
}
public void setWorkingDirectory(final File dir)
{
if (dir != null) {
if (dir.exists()) {
if (!dir.isDirectory()) {
throw new IllegalArgumentException
("Directory argument does not point to a directory: " + dir);
}
}
}
this.workingDir = dir;
}
public File getWorkingDirectory()
{
return workingDir;
}
public Integer getExitValue()
{
if (childProcess != null) {
return new Integer(childProcess.exitValue());
}
return null;
}
public void setLoggerAdapterName(final String name)
{
this.loggerAdapterName = name;
}
public String getLoggerAdapterName()
{
return loggerAdapterName;
}
protected String[] makeEnvArray(final Properties props)
{
if (props == null)
return new String[0];
String[] envArray = new String[props.keySet().size()];
Iterator iter = props.keySet().iterator();
int i = 0;
while (iter.hasNext()) {
String name = (String)iter.next();
envArray[i++] = name + "=" + props.getProperty(name);
}
return envArray;
}
protected static class ReaderLoggerAdapter
implements Runnable
{
protected BufferedReader reader;
protected boolean shutdown;
protected Logger log;
protected Level level;
public ReaderLoggerAdapter(final Reader reader, final Logger log, final Level level)
{
if (reader instanceof BufferedReader) {
this.reader = (BufferedReader)reader;
}
else {
this.reader = new BufferedReader(reader);
}
this.log = log;
this.level = level;
}
public ReaderLoggerAdapter(final InputStream input, final Logger log, final Level level)
{
this(new InputStreamReader(input), log, level);
}
public void shutdown()
{
shutdown = true;
}
public void run()
{
while (!shutdown) {
try {
String data = reader.readLine();
if (data == null) {
try {
Thread.sleep(1000);
}
catch (InterruptedException ignore) {}
}
else {
log.log(level, data);
}
}
catch (IOException e) {
log.error("Failed to read data from reader", e);
}
}
}
}
protected void startService() throws Exception
{
Runtime rt = Runtime.getRuntime();
childProcess = rt.exec(commandLine, makeEnvArray(env), workingDir);
log.info("Spawned child process: " + commandLine);
Logger logger = Logger.getLogger(loggerAdapterName);
InputStream input = childProcess.getInputStream();
inputAdapter = new ReaderLoggerAdapter(input, logger, Level.INFO);
new Thread(inputAdapter).start();
InputStream error = childProcess.getErrorStream();
errorAdapter = new ReaderLoggerAdapter(error, logger, Level.ERROR);
new Thread(errorAdapter).start();
}
protected void stopService() throws Exception
{
childProcess.destroy();
log.debug("Child process destroyed; waiting for process to exit");
childProcess.waitFor();
log.info("Child exited with code: " + getExitValue());
inputAdapter.shutdown();
errorAdapter.shutdown();
childProcess = null;
inputAdapter = null;
errorAdapter = null;
}
}