Execution.java [src/java/m/rse/cfactor/utils] Revision: default Date:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package m.rse.cfactor.utils;
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* 2010-2013, Olaf David and others, Colorado State University.
*
* CSIP is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1.
*
* CSIP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OMS. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
*/
import csip.SessionLogger;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Executable. Helper class to execute external programs.
*
* @author od
*/
class Execution {
private final ProcessBuilder pb = new ProcessBuilder();
private final File executable;
private Object[] args = new Object[]{};
private SessionLogger logger;
//
Writer stderr = new OutputStreamWriter(System.err) {
@Override
public void close() throws IOException {
System.err.flush();
}
};
//
Writer stdout = new OutputStreamWriter(System.out) {
@Override
public void close() throws IOException {
System.out.flush();
}
};
/**
* Create a new ProcessExecution.
*
* @param executable the executable file.
*/
Execution(File executable) {
this.executable = executable;
}
File getFile() {
return executable;
}
/**
* Set the execution arguments.
*
* @param args the command line arguments
*/
void setArguments(Object... args) {
this.args = args;
}
/**
* Set the execution arguments.
*
* @param args the command line arguments
*/
void setArguments(String... args) {
this.args = args;
}
/**
* Set the execution arguments.
*
* @param args the program arguments.
*/
void setArguments(List<Object> args) {
this.args = args.toArray(new Object[args.size()]);
}
/**
* Get the arguments
*
* @return
*/
Object[] getArguments() {
Object[] ar = new Object[args.length];
System.arraycopy(args, 0, ar, 0, ar.length);
return ar;
}
/**
* Set the working directory where the process get executed.
*
* @param dir the directory in which the executable will be started
*/
void setWorkingDirectory(File dir) {
if (!dir.exists() || dir.isFile()) {
throw new IllegalArgumentException("directory " + dir + " doesn't exist.");
}
pb.directory(dir);
}
/**
* get the execution environment. Use the returned map to customize the
* environment variables.
*
* @return the process environment.
*/
Map<String, String> environment() {
return pb.environment();
}
/**
* Set the logger. This is optional.
*
* @param log the logger
*/
void setLogger(SessionLogger log) {
this.logger = log;
}
/**
* Output handler for stdout/stderr
*/
private static class OutputHandler extends Thread {
Writer w;
Reader r;
CountDownLatch l;
OutputHandler(CountDownLatch l, InputStream is, Writer w) {
r = new InputStreamReader(is);
this.w = w;
this.l = l;
setPriority(Thread.MIN_PRIORITY);
}
@Override
public void run() {
try {
char[] b = new char[2048];
int n = r.read(b);
while (n != -1) {
w.write(b, 0, n);
w.flush();
n = r.read(b);
}
} catch (IOException ex) {
if (ex.getMessage().equals("Stream closed.")) {
return;
}
ex.printStackTrace(System.err);
} finally {
try {
w.flush();
w.close();
r.close();
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
l.countDown();
}
}
}
/**
* Process execution. This call blocks until the process is done.
*
* @return the exit status of the process. 0 = all good
* @throws java.io.IOException
*/
int exec() throws IOException {
List<String> cmd = new ArrayList<>();
cmd.add(executable.toString());
for (Object arg : args) {
if (arg != null) {
if (arg.getClass() == String[].class) {
for (String s : (String[]) arg) {
if (s != null && !s.isEmpty()) {
cmd.add(s);
}
}
} else {
cmd.add(arg.toString());
}
}
}
pb.command(cmd);
if (logger != null && logger.isLoggable(Level.INFO)) {
logger.info(pb.command().toString());
}
CountDownLatch l = new CountDownLatch(2);
Process p = pb.start();
new OutputHandler(l, p.getInputStream(), stdout).start();
new OutputHandler(l, p.getErrorStream(), stderr).start();
int exitValue = 0;
try {
exitValue = p.waitFor();
l.await();
} catch (InterruptedException E) {
// do nothing
} finally {
p.getOutputStream().close();
p.destroy();
}
return exitValue;
}
/**
* Redirect the output stream
*
* @param w the stream handler
*/
void redirectOutput(Writer w) {
if (w == null) {
throw new NullPointerException("w");
}
stdout = w;
}
/**
* Redirect the error stream
*
* @param w the new handler.
*/
void redirectError(Writer w) {
if (w == null) {
throw new NullPointerException("w");
}
stderr = w;
}
public static void main(String[] args) throws IOException {
// SessionLogger l = new SessionLogger(new File("/tmp"), "", "");
System.out.println("exec");
// Execution e = new Execution(new File("/od/projects/csip-all/csip-example/src/C/mod.exe"));
Execution e = new Execution(new File("mod.exe"));
e.setArguments("1", "2", "3");
// Execution e = new Execution(new File("/bin/bash"));
// e.setArguments("-c","ls -l");
e.setWorkingDirectory(new File("/home/od"));
// e.setLogger(l);
System.out.println(e.environment().get("PATH"));
String p = e.environment().get("PATH");
p = p + File.pathSeparator + "/od/projects/csip-all/csip-example/src/C";
e.environment().put("PATH", p);
System.out.println(e.environment().get("PATH"));
int r = e.exec();
System.out.println("return " + r);
}
}