/*
This file is part of JFLICKS.
JFLICKS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JFLICKS 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JFLICKS. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jflicks.job;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.jflicks.util.LogUtil;
import org.jflicks.util.Util;
/**
* This class will run any system executable. It uses Input and Output jobs
* to monitor and control stdin and stdout from the system process.
*
* @author Doug Barnum
* @version 1.0
*/
public final class SystemJob extends AbstractJob implements JobListener {
private String shell;
private String shellSwitch;
private String command;
private File working;
private String outputText;
private Process process;
private int exitValue;
private InputStreamJob inputStreamJob;
private JobContainer inputJobContainer;
private OutputStreamJob outputStreamJob;
private JobContainer outputJobContainer;
private SystemJob() {
}
private SystemJob(String shell, String shellSwitch, String command,
File working) {
setShell(shell);
setShellSwitch(shellSwitch);
setCommand(command);
setWorking(working);
}
/**
* We control the instances of these jobs because they are configured
* differently based upon platform. This insulates the user from
* worrying about these details.
*
* @param command The command line arguments (including program name).
* @return A SystemJob instance that can be controlled with a JobContainer.
*/
public static SystemJob getInstance(String command) {
SystemJob result = null;
boolean win = false;
if (Util.isWindows()) {
result = new SystemJob("cmd.exe", "/C", command, null);
} else {
//} else if (Util.isLinux()) {
result = new SystemJob("/bin/bash", "-c", command, null);
}
return (result);
}
/**
* We control the instances of these jobs because they are configured
* differently based upon platform. This insulates the user from
* worrying about these details.
*
* @param command The command line arguments (including program name).
* @return A SystemJob instance that can be controlled with a JobContainer.
*/
public static SystemJob getInstance(String command, File working) {
SystemJob result = null;
boolean win = false;
if (Util.isWindows()) {
result = new SystemJob("cmd.exe", "/C", command, working);
} else {
//} else if (Util.isLinux()) {
result = new SystemJob("/bin/bash", "-c", command, working);
}
return (result);
}
private String getShell() {
return (shell);
}
private void setShell(String s) {
shell = s;
}
private String getShellSwitch() {
return (shellSwitch);
}
private void setShellSwitch(String s) {
shellSwitch = s;
}
/**
* The input command defining the system call.
*
* @return The command string.
*/
public String getCommand() {
return (command);
}
private void setCommand(String s) {
command = s;
}
/**
* The input command defining the system call.
*
* @return The command string.
*/
public File getWorking() {
return (working);
}
private void setWorking(File f) {
working = f;
}
/**
* All output from the job. Available on job completion.
*
* @return The output as a string.
*/
public String getOutputText() {
return (outputText);
}
private void setOutputText(String s) {
outputText = s;
}
public Process getProcess() {
return (process);
}
private void setProcess(Process p) {
process = p;
}
/**
* The exit value from the operating system on job completion.
*
* @return An exit value as an int.
*/
public int getExitValue() {
return (exitValue);
}
private void setExitValue(int i) {
exitValue = i;
}
/**
* Write to the stdin of the system process.
*
* @param array A byte array of data.
* @param offset The offset into the array.
* @param length The number of bytes to write.
* @throws IOException on error.
*/
public void write(byte[] array, int offset, int length) throws IOException {
if ((outputStreamJob != null) && (array != null)) {
outputStreamJob.write(array, offset, length);
}
}
/**
* {@inheritDoc}
*/
public void jobUpdate(JobEvent event) {
if (event.getType() != JobEvent.COMPLETE) {
fireJobEvent(event);
}
}
/**
* {@inheritDoc}
*/
public void start() {
ProcessBuilder pb = new ProcessBuilder(getShell(), getShellSwitch(), getCommand());
if (pb != null) {
try {
// We want to set the PATH variable in case a System
// property is set.
String jflicksPath = System.getProperty("jflicks.path");
LogUtil.log(LogUtil.DEBUG, "jflicks.path: <" + jflicksPath + ">");
if (jflicksPath != null) {
jflicksPath = jflicksPath.replaceAll("\\\\", "/");
String pathsep = System.getProperty("path.separator");
Map<String, String> env = pb.environment();
String oldpath = env.get("PATH");
if (oldpath != null) {
env.put("PATH", jflicksPath + pathsep + oldpath);
} else {
env.put("PATH", jflicksPath);
}
}
File dir = getWorking();
if (dir != null) {
pb.directory(dir);
}
pb.redirectErrorStream(true);
setProcess(pb.start());
} catch (Exception ex) {
setProcess(null);
}
}
}
/**
* {@inheritDoc}
*/
public void run() {
Process p = getProcess();
if (p != null) {
try {
inputStreamJob = new InputStreamJob(p.getInputStream());
inputJobContainer = JobManager.getJobContainer(inputStreamJob);
outputStreamJob = new OutputStreamJob(p.getOutputStream());
outputJobContainer =
JobManager.getJobContainer(outputStreamJob);
if ((inputStreamJob != null) && (inputJobContainer != null)
&& (outputStreamJob != null)
&& (outputJobContainer != null)) {
inputStreamJob.addJobListener(this);
inputJobContainer.start();
JobManager.sleep(1000);
outputStreamJob.addJobListener(this);
outputJobContainer.start();
JobManager.sleep(1000);
setExitValue(p.waitFor());
setOutputText(inputStreamJob.getOutputText());
inputJobContainer.stop();
inputJobContainer = null;
inputStreamJob.removeJobListener(this);
inputStreamJob = null;
outputJobContainer.stop();
outputJobContainer = null;
outputStreamJob.removeJobListener(this);
outputStreamJob = null;
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
setTerminate(true);
fireJobEvent(JobEvent.COMPLETE);
}
/**
* {@inheritDoc}
*/
public void stop() {
setTerminate(true);
Process p = getProcess();
if (p != null) {
try {
p.destroy();
setExitValue(p.waitFor());
setProcess(null);
if (inputJobContainer != null) {
inputJobContainer.stop();
inputStreamJob.removeJobListener(this);
}
if (outputJobContainer != null) {
outputJobContainer.stop();
outputStreamJob.removeJobListener(this);
}
} catch (Exception ex) {
System.err.println(ex.getMessage());
ex.printStackTrace();
}
}
}
}