package net.sourceforge.dita4publishers.tools.imaging.im; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.LinkedList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This class implements the processing of os-commands using Runtime.exec(). */ public class ProcessStarter { private static Log log = LogFactory.getLog(ProcessStarter.class); /** * Buffer size of process input-stream (used for reading the output (sic!) of * the process). Currently 64KB. */ public static final int BUFFER_SIZE = 65536; /** * The InputProvider for the ProcessStarter (if used as a pipe). */ private InputProvider iInputProvider = null; /** * The OutputConsumer for the ProcessStarter (if used as a pipe). */ private OutputConsumer iOutputConsumer = null; /** * The ErrorConsumer for the stderr of the ProcessStarter. */ private ErrorConsumer iErrorConsumer = null; /** * Execution-mode. If true, run asynchronously. */ private boolean iAsyncMode = false; /** * The ProcessListeners for this ProcessStarter. */ private LinkedList<ProcessListener> iProcessListener; /** * Constructor. */ protected ProcessStarter() { iProcessListener = new LinkedList<ProcessListener>(); } /** * Set the InputProvider for the ProcessStarter (if used as a pipe). */ public void setInputProvider( InputProvider pInputProvider) { iInputProvider = pInputProvider; } /** * Set the OutputConsumer for the ProcessStarter (if used as a pipe). */ public void setOutputConsumer( OutputConsumer pOutputConsumer) { iOutputConsumer = pOutputConsumer; } /** * Set the ErrorConsumer for the stderr of the ProcessStarter. */ public void setErrorConsumer( ErrorConsumer pErrorConsumer) { iErrorConsumer = pErrorConsumer; } /** * Add a ProcessListener to this ProcessStarter. * * @param pProcessListener * the ProcessListener to add */ public void addProcessListener( ProcessListener pProcessListener) { iProcessListener.add(pProcessListener); } /** * Pipe input to the command. This is done asynchronously. */ private void processInput( OutputStream pOutputStream) throws IOException { final BufferedOutputStream bos = new BufferedOutputStream(pOutputStream, BUFFER_SIZE); (new Thread() { public void run() { try { iInputProvider.provideInput(bos); } catch (IOException iex) { // we do nothing, since we are in an asynchronous thread anyway } } }).run(); bos.close(); if (pOutputStream != null) { pOutputStream.close(); } } /** * Let the OutputConsumer process the output of the command. */ private void processOutput( InputStream pInputStream, OutputConsumer pConsumer) throws IOException { BufferedInputStream bis = new BufferedInputStream(pInputStream, BUFFER_SIZE); pConsumer.consumeOutput(bis); bis.close(); if (pInputStream != null) { pInputStream.close(); } } /** * Let the ErrorConsumer process the stderr-stream. */ private void processError( InputStream pInputStream, ErrorConsumer pConsumer) throws IOException { BufferedInputStream bis = new BufferedInputStream(pInputStream, BUFFER_SIZE); pConsumer.consumeError(bis); bis.close(); if (pInputStream != null) { pInputStream.close(); } } /** * Execute the command. */ protected int run( final LinkedList<String> pArgs) throws IOException, InterruptedException { if (!iAsyncMode) { Process pr = startProcess(pArgs); return waitForProcess(pr); } else { Runnable r = new Runnable() { public void run() { int rc; ProcessEvent pe = new ProcessEvent(); try { Process pr = startProcess(pArgs); for (ProcessListener pl : iProcessListener) { pl.processStarted(pr); } rc = waitForProcess(pr); pe.setReturnCode(rc); } catch (Exception e) { pe.setException(e); } for (ProcessListener pl : iProcessListener) { pl.processTerminated(pe); } } }; (new Thread(r)).start(); return 0; } } /** * Execute the command. */ private Process startProcess( LinkedList<String> pArgs) throws IOException, InterruptedException { ProcessBuilder builder = new ProcessBuilder(pArgs); if (log.isDebugEnabled()) { for (String arg: pArgs) log.debug("arg: "+arg); } return builder.start(); } /** * Perform process input/output and wait for process to terminate. */ private int waitForProcess( Process pProcess) throws IOException, InterruptedException { if (iInputProvider != null) { processInput(pProcess.getOutputStream()); } if (iOutputConsumer != null) { processOutput(pProcess.getInputStream(), iOutputConsumer); } if (iErrorConsumer != null) { processError(pProcess.getErrorStream(), iErrorConsumer); } pProcess.waitFor(); int rc = pProcess.exitValue(); // just to be on the safe side try { pProcess.getInputStream().close(); pProcess.getOutputStream().close(); pProcess.getErrorStream().close(); } catch (Exception e) { } return rc; } /** * @param pAsyncMode * the iAsyncMode to set */ public void setAsyncMode( boolean pAsyncMode) { iAsyncMode = pAsyncMode; } /** * @return the iAsyncMode */ public boolean isAsyncMode() { return iAsyncMode; } }