/*******************************************************************************
* Copyright (c) 2012-2015 INRIA.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Generoso Pagano - initial API and implementation
******************************************************************************/
package fr.inria.soctrace.framesoc.core.tools.management;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ProcessBuilder.Redirect;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base wrapper for external program execution in Eclipse.
*
* <pre>
* The class provides two execute() methods for executing a program:
* - a "push style" method, which pushes each line of output to a line processor
* (data pushed to the client code)
* - a "pop style" method, which provides the client code with a BufferedReader
* (data popped by the client code)
* </pre>
*
* @author "Generoso Pagano <generoso.pagano@inria.fr>"
*/
public class ExternalProgramWrapper {
private final static Logger logger = LoggerFactory.getLogger(ExternalProgramWrapper.class);
/**
* Program command with arguments
*/
protected List<String> fCommand;
/**
* Constructor
*
* @param command
* program command
* @param arguments
* command arguments
*/
public ExternalProgramWrapper(String command, List<String> arguments) {
super();
if (command == null)
throw new NullPointerException();
if (arguments == null)
throw new NullPointerException();
fCommand = new ArrayList<>(arguments.size() + 1);
fCommand.add(command);
fCommand.addAll(arguments);
}
/**
* Execute the external program, passing the command stdout and stderr to
* the given processor.
*
* The external program is destroyed if the progress monitor is stopped.
*
* @param monitor
* progress monitor
* @param processor
* line processor
* @return the execution status
*/
public IStatus execute(IProgressMonitor monitor, ILineProcessor processor) {
logger.debug("Executing: {}", fCommand);
try {
ProcessBuilder pb = new ProcessBuilder(fCommand);
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.PIPE);
Process p = pb.start();
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = bri.readLine()) != null && !monitor.isCanceled()) {
processor.process(line);
}
bri.close();
p.destroy();
} catch (IOException e) {
System.err.println(e.getMessage());
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
/**
* Execute the external program, immediately returning a buffered reader to
* get the command stdout and stderr.
*
* The program is destroyed if the progress monitor is cancelled.
*
* @param monitor
* progress monitor
* @return the buffered reader to read program stdout and stderr
*/
public BufferedReader execute(final IProgressMonitor monitor) {
logger.debug("Executing: {}", fCommand);
try {
ProcessBuilder pb = new ProcessBuilder(fCommand);
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.PIPE);
final Process p = pb.start();
Thread watchDog = new Thread() {
@Override
public void run() {
boolean exited = false;
while (!monitor.isCanceled() && !exited) {
try {
p.exitValue();
exited = true;
} catch (IllegalThreadStateException e) {
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
if (!exited) {
p.destroy();
}
}
};
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
watchDog.start();
return br;
} catch (IOException e) {
System.err.println(e.getMessage());
return null;
}
}
}