How to create a process in Java
There is only one way to create processes in Java, Runtime.exec()
- basically it allows you to start a new JVM just as you would via the command line interface.
Create a new process in Java, exit the current process
Update: I did find the right answer and it might be a bit complex, but I shall try to make it as simple as possible.
In this, we will require 2 separate classes: 1 class to monitor the child process, 1 class which is the main process.
For the sake of simplicity, I shall name the monitoring class as SessionManager
and the main class as mainClass
In the SessionManager class, I've implemented the following code.
try
{
//A loop which will run infinitely to montior and start new processes
while(true)
{
//Create the process and listen to the exit code generated by the child process spawned.
ProcessBuilder session_monitor=new ProcessBuilder("java", "<classname>");
Process process_monitor= session_monitor.inheritIO().start();
//wait for the child process to end before proceeding
process_monitor.waitFor();
switch(process_monitor.exitValue())
{
//Implement the logic here
case 0: //do something
break;
case 1: //do something
break;
}
}
}
catch(Exception E)
{
E.printStackTrace();
}
And in the mainClass
program, we shall have a main method to start the process running.
class mainClass
{
public static void main(String[] args)
{
System.out.println("Hello World");
//exit the process with a code for the SessionManager's logic to work
System.exit(0); //Using a normal exit code here
}
}
This has worked for me, and if you think this implementation can be improved, I'd love to hear it. Thank you for all your support :)
Is it possible to create a java.lang.Process instance for a process started not from my code?
In short, not with Java ≤ 8, but it is possible with Java 9 and java.lang.ProcessHandle
.
A Process
in Java is not meant to model an arbitrary OS process, it actually models a sub-process of the java process, so you can't attach to another running process, and expect to get all features a Process
has:
The class Process provides methods for performing input from the process, performing output to the process, waiting for the process to complete, checking the exit status of the process, and destroying (killing) the process.
As you see, input and output requires your java process to have a handle on the other process's stdin/stdout/stderr, which only makes sense for a child process. The doc also mentions "the subprocess" everywhere, thus implying it's a child process.
In Java 9 the doc explicitly starts with:
Process provides control of native processes started by
ProcessBuilder.start
andRuntime.exec
.
But Java 9 also brings ProcessHandle
, which is exactly what you need:
ProcessHandle
identifies and provides control of native processes. Each individual process can be monitored for liveness, list its children, get information about the process or destroy it. By comparison,Process
instances were started by the current process and additionally provide access to the process input, output, and error streams.
So, if you can run your tests with Java 9, you can try using ProcessHandle.allProcesses()
to find the process you want, and then kill it with .destroy()
, monitor its liveness with isAlive()
, or use onExit()
.
Optional<ProcessHandle> optional = ProcessHandle.allProcesses().filter(process -> {
Optional<String> command = process.info().command();
return command.isPresent() && command.get().equals("Chromedriver.exe");
}).findFirst();
if (optional.isPresent()) {
ProcessHandle processHandle = optional.get();
System.out.println("Killing process " + processHandle.pid());
processHandle.destroy();
try {
System.out.println("Waiting for process " + processHandle.pid() + " to exit...");
processHandle.onExit().get();
System.out.println("Done !");
} catch (InterruptedException|ExecutionException e) {
e.printStackTrace();
}
}
That being said, if you really want to, you can create a subclass of Process
by yourself, that will provide limited functionality (ie nothing about I/O, only waitFor
and destroy
& such).
Below is an awful example quickly hacked using ideas from this Q&A for the Windows implementation.
- find process by name using
tasklist /FO CSV /FI "IMAGENAME eq Chromedriver.exe", to get the PID
- kill it with
taskkill
- wait for it to end with a polling-loop that uses
tasklist
/FO CSV /FI "PID eq ..."
The Linux version uses pgrep
, kill
, and /proc/{pid}/
.
Please note it's not really useful to wrap that as an actual instance of java.lang.Process
, so I've separated the concerns with a tool class that implements the required features for windows, and a subclass of Process
implemented as an exercise to show what's possible, and what is not possible (details in code). So if you need that, better use ProcessTool
directly, not DummyProcess
.
(I've tested this on another process, I can't speak for Chromedriver.exe
, you might need to adapt a few details)
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Paths;
import java.util.Scanner;
public class WaitForProcessDemo {
public static void main(String[] args) throws IOException, InterruptedException {
Process p = getDummyProcess("Chromedriver");
System.out.println("Killing...");
p.destroy();
System.out.println("Waiting...");
p.waitFor();
System.out.println("Done.");
}
private static Process getDummyProcess(String exeName) throws IOException {
ProcessTool tool = new WindowsProcessTool();
long pid = tool.findProcessByName(exeName);
return new DummyProcess(pid, tool);
}
interface ProcessTool {
long findProcessByName(String exeName) throws IOException;
void killProcess(long pid) throws IOException;
boolean isPidStillThere(long pid);
}
private static class WindowsProcessTool implements ProcessTool {
@Override
public long findProcessByName(String exeName) throws IOException {
String processInfoCSV = findProcessInfoCSV("IMAGENAME eq " + exeName);
String[] fields = processInfoCSV.split("\"");
String pid = fields[3];
return Integer.parseInt(pid);
}
String findProcessInfoCSV(String filter) throws IOException {
Process p = new ProcessBuilder("tasklist", "-FO", "CSV", "/FI", filter)
.redirectErrorStream(true)
.start();
Scanner scanner = new Scanner(p.getInputStream());
scanner.nextLine(); // skip header line
if (scanner.hasNextLine()) {
return scanner.nextLine();
}
throw new IOException("No such process: " + filter);
}
@Override
public void killProcess(long pid) throws IOException {
new ProcessBuilder("taskkill", "/PID", String.valueOf(pid))
.redirectErrorStream(true)
.start();
}
@Override
public boolean isPidStillThere(long pid) {
try {
findProcessInfoCSV("PID eq " + pid);
return true;
} catch (IOException e) {
return false;
}
}
}
private static class LinuxProcessTool implements ProcessTool {
@Override
public long findProcessByName(String exeName) throws IOException {
Process pgrep = new ProcessBuilder("pgrep", exeName)
.redirectErrorStream(true)
.start();
Scanner scanner = new Scanner(pgrep.getInputStream());
return Long.parseLong(scanner.nextLine());
}
@Override
public void killProcess(long pid) throws IOException {
new ProcessBuilder("kill", String.valueOf(pid))
.redirectErrorStream(true)
.start();
}
@Override
public boolean isPidStillThere(long pid) {
return Paths.get("/proc", String.valueOf(pid)).toFile().isDirectory();
}
}
/*
* Broken & incomplete implementation of java.lang.Process, implemented as an exercise.
* (Kids, don't do this at home)
*/
static class DummyProcess extends Process {
private final long pid;
private final ProcessTool tool;
DummyProcess(long pid, ProcessTool tool) {
this.pid = pid;
this.tool = tool;
}
@Override
public OutputStream getOutputStream() {
return null; // DANGER. This cannot be implemented for non-child process.
}
@Override
public InputStream getInputStream() {
return null; // DANGER. This cannot be implemented for non-child process.
}
@Override
public InputStream getErrorStream() {
return null; // DANGER. This cannot be implemented for non-child process.
}
@Override
public int waitFor() throws InterruptedException {
// Very sub-optimal implementation
boolean isPidPresent = isPidStillThere();
while (isPidPresent) {
Thread.sleep(500);
isPidPresent = isPidStillThere();
}
return 0;
}
@Override
public int exitValue() {
// For example, this is dangerous, as Process.isAlive() will call this, and determine process is not alive.
// Also, it cannot be implemented correctly, it's not possible to tell what was exit value.
// At best we could throw IllegalThreadStateException when process is still alive.
return 0;
}
@Override
public void destroy() {
try {
tool.killProcess(pid);
} catch (IOException e) {
throw new RuntimeException("Failed to kill process " + pid, e);
}
}
private boolean isPidStillThere() {
return tool.isPidStillThere(pid);
}
}
}
Starting a process in Java?
http://www.rgagnon.com/javadetails/java-0014.html
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.file.Paths;
public class CmdExec {
public static void main(String args[]) {
try {
// enter code here
Process p = Runtime.getRuntime().exec(
Paths.get(System.getenv("windir"), "system32", "tree.com /A").toString()
);
// enter code here
try(BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while ((line = input.readLine()) != null) {
System.out.println(line);
}
}
} catch (Exception err) {
err.printStackTrace();
}
}
}
You can get the local path using System properties or a similar approach.
http://download.oracle.com/javase/tutorial/essential/environment/sysprop.html
How to create a process on node from a JVM which is running other node
If it is the same machine (jvm and python script), you can leverage ProcessBuilder class itself to execute script directly.
In case of script residing on another box, you can leverage JSch library which provides you ssh capabilities to launch process on remote machine.
How to create bpmn2 process flow programmatically in Eclipse?
You can use Fluent API [1][2] to programatically create process definition.
I am not sure if you can set X-Y coordinates of respective nodes, so can't confirm that importing *.BPMN file generated with this API into a BPMN designer will render properly - but it will be definitely executable.
[1] https://github.com/kiegroup/jbpm/blob/master/jbpm-bpmn2/src/test/java/org/jbpm/bpmn2/ProcessFactoryTest.java#L70
[2] https://docs.jboss.org/jbpm/release/7.33.0.Final/jbpm-docs/html_single/#_process_fluent_api
Related Topics
Why Integer.Max_Value + 1 == Integer.Min_Value
How to Change Background Color of Jtabbedpane
Numeric Textfield for Integers in Javafx 8 with Textformatter And/Or Unaryoperator
Possible to Use Two Java Classes with Same Name and Same Package
Getting Value of Public Static Final Field/Property of a Class in Java via Reflection
What Are Shadow Variables in Java
How to Emit and Handle Custom Events
Swing - Thread.Sleep() Stop Jtextfield.Settext() Working
How to Use the Unsigned Integer in Java 8 and Java 9
What Does Super.Paintcomponent(G) Do
How to Create a New Packaging Type for Maven
Superclass Reference Not Able to Call Subclass Method in Java
Circular Dependency in Java Constructors