How to Create a Process in Java

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 and Runtime.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



Leave a reply



Submit