package com.revolsys.process;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JOptionPane;
import com.revolsys.collection.list.Lists;
import com.revolsys.io.FileUtil;
import com.revolsys.logging.Logs;
import com.revolsys.parallel.ThreadInterruptedException;
public final class JavaProcess implements Runnable {
private List<String> javaArguments = new ArrayList<>();
private List<String> programArguments = new ArrayList<>();
private Class<?> programClass;
private File logFile;
private Runnable completedAction;
public JavaProcess() {
}
public JavaProcess(final Class<?> programClass) {
this(null, programClass, null);
}
public JavaProcess(final List<String> javaArguments, final Class<?> programClass,
final List<String> programArguments) {
this.javaArguments = Lists.toArray(javaArguments);
this.programArguments = Lists.toArray(programArguments);
this.programClass = programClass;
}
public JavaProcess(final List<String> javaArguments, final List<String> programArguments) {
this(javaArguments, null, programArguments);
}
public JavaProcess addJavaArgument(final int index, final String argument) {
this.javaArguments.add(index, argument);
return this;
}
public JavaProcess addJavaArgument(final String argument) {
this.javaArguments.add(argument);
return this;
}
public JavaProcess addProgramArgument(final int index, final String argument) {
this.programArguments.add(index, argument);
return this;
}
public JavaProcess addProgramArgument(final String argument) {
this.programArguments.add(argument);
return this;
}
public List<String> getJavaArguments() {
return this.javaArguments;
}
public File getLogFile() {
return this.logFile;
}
public List<String> getProgramArguments() {
return this.programArguments;
}
public Class<?> getProgramClass() {
return this.programClass;
}
public ProcessBuilder newBuilder() {
final String javaHome = System.getProperty("java.home");
final String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
final List<String> params = new ArrayList<>();
params.add(javaBin);
params.add("-cp");
final String classpath = System.getProperty("java.class.path");
params.add(classpath);
final String libraryPath = System.getProperty("java.library.path");
params.add("-Djava.library.path=" + libraryPath);
final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
final List<String> inputArguments = runtimeMXBean.getInputArguments();
for (final String inputArgument : inputArguments) {
if (!inputArgument.startsWith("-agentlib")
&& !Arrays.asList("abort", "exit").contains(inputArgument)) {
params.add(inputArgument);
}
}
params.addAll(this.javaArguments);
final String className = this.programClass.getCanonicalName();
params.add(className);
params.addAll(this.programArguments);
final ProcessBuilder builder = new ProcessBuilder(params);
if (this.logFile != null) {
this.logFile = FileUtil.getFile(this.logFile);
this.logFile.getParentFile().mkdirs();
builder.redirectErrorStream(true);
builder.redirectOutput(this.logFile);
}
return builder;
}
@Override
public void run() {
if (this.programClass == null) {
Logs.error(this, "programClass cannot be null");
} else {
try {
final int exitValue = startAndWait();
if (exitValue != 0) {
JOptionPane.showMessageDialog(
null, "<html>Error ruunning process, check log file for details<br /><code>"
+ this.logFile + "</code></html>",
"Error running process", JOptionPane.ERROR_MESSAGE);
}
if (this.completedAction != null) {
this.completedAction.run();
}
} catch (final Throwable e) {
Logs.error(this.programClass, e);
} finally {
try {
if (this.completedAction != null) {
this.completedAction.run();
}
} catch (final Throwable e) {
Logs.error(this.programClass, e);
}
}
}
}
public void setCompletedAction(final Runnable completedAction) {
this.completedAction = completedAction;
}
public JavaProcess setJavaArguments(final List<String> javaArguments) {
this.javaArguments = Lists.toArray(javaArguments);
return this;
}
public JavaProcess setLogFile(final File logFile) {
this.logFile = logFile;
return this;
}
public JavaProcess setProgramArguments(final List<String> programArguments) {
this.programArguments = Lists.toArray(programArguments);
return this;
}
public JavaProcess setProgramClass(final Class<?> programClass) {
this.programClass = programClass;
return this;
}
public Process start() {
final ProcessBuilder processBuilder = newBuilder();
try {
return processBuilder.start();
} catch (final Throwable e) {
throw new RuntimeException("Unable to start " + processBuilder.command(), e);
}
}
public int startAndWait() {
final Process process = start();
try {
process.waitFor();
} catch (final InterruptedException e) {
throw new ThreadInterruptedException(e);
}
return process.exitValue();
}
public Thread startThread() {
if (this.programClass == null) {
Logs.error(this, "programClass cannot be null");
return null;
} else {
final Thread thread = new Thread(this, this.programClass.getName());
thread.start();
return thread;
}
}
}