Is it possible in Java to seperate a subprocess so that it isn't longer a subprocess in the end?
Or to run a external process, that isn't a subprocess.
I want to start some big external process in linux. But with ProcessBuilder or Runtime.exec, it's my subprocesses and when I try to start big processes for example four minecraft server, I get a pthread_create exception in the end.
Is this possible in Java?
I just tested a small sample
import java.io.IOException;
public class Forking {
public static void main(String[] args) {
Process exec = null;
try {
exec = Runtime.getRuntime().exec("sleep 360");
} catch (IOException e) {
e.printStackTrace();
}
if (exec != null) {
System.out.println(exec.isAlive());
}
}
}
It runs with no exceptions and after it exits if you ps aux|grep sleep you will see that the sleep 360 is there running.
Related
My Java programme starts several other Java processes. When the programme is closed, all created processes should be terminated.
If the programme is stopped via an internal stop command, all data can be saved and the processes shut down. I use a shutdown hook for this, and it works very well so far.
But if the programme terminates abruptly or is not closed correctly by the user, all processes remain running and the programme does not work the next time it is started.
How can I make it so that code is executed when the programme stops abruptly, or rather, how can I stop the processes?
As suggested, I should have included some code. Here is a simplified version of the code:
Class which starts the process:
#Override
public void startProcess() throws IOException {
String command = "java -jar server.jar nogui";
this.process = Runtime.getRuntime().exec(command, null, new CloudFolder(super.getPath()).get());
final InputReader reader = new InputReader();
reader.open();
String in = reader.getInput();
if (in.equals("stop")) {
this.process.destroy();
this.process.getOutputStream().close();
}
}
Main class:
public static void main(String[] args) {
// normally the startProcess() Method would be
// called right here.
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
// Just to see if it worked
File file = new File("closing");
try {
file.createNewFile();
} catch (IOException exception) {
exception.printStackTrace();
}
}
}, "Shutdown-thread"));
}
I am writing a program in which I want to start a shell in the background, and send and receive the input and output. I already have managed to do this, and can successfully read and write to this process. This is where I run into trouble.
I would like to have a method in ShellManager (see below code) that waits until whatever the process is doing finishes/fails, and returns input to the user.
For example, if I send tar xzf something_that_will_take_a_while.tar.gz,
I can see in the output how it takes its time, and then echoes this:
]0;~
[32mMe#MyComputer [33m~[0m
I already tried blocking the thread until ]0;~ was received, this did not work. (Never returned)
I also tried \u001B, same problem :(
I'm not sure what the symbol is, and can't find much on how to detect when the process returns.
Here is my code:
package buildSystem.shell;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import base.TermConstants;
public class ShellManager {
private InputStream termOut;
private OutputStream termIn;
private ProcessBuilder build;
private Process main;
BufferedReader reader;
BufferedWriter writer;
public ShellManager() {
build = new ProcessBuilder(TermConstants.getShellLocation());
build.redirectErrorStream(true);
}
public void start() throws IOException {
try {
main = build.start();
termOut = main.getInputStream();
termIn = main.getOutputStream();
reader = new BufferedReader (new InputStreamReader(termOut));
writer = new BufferedWriter(new OutputStreamWriter(termIn));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void writeLine(String s) throws IOException {
writer.write(s);
writer.newLine();
writer.flush();
}
public String readNextLine() throws IOException {
return reader.readLine();
}
public void end() {
try {
writeLine("exit\n");
main.waitFor();
termOut.close();
termIn.close();
reader.close();
writer.close();
} catch (IOException | InterruptedException e) {
kill();
}
}
public void kill() {
main.destroyForcibly();
try {
termOut.close();
termIn.close();
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*THE PART I AM HAVING TROUBLE WITH:*/
public void waitForReturn() {
try {
while(reader.readLine() != "\u001B") {}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Basically, I want a reliable way to detect when a program exits from a bash shell. The bash process will still be running, but the program running from that bash instance will have returned. Because of this I cannot use process.waitFor().
I tried waiting for ]0;~, and then the [32mMe#MyComputer [33m~[0m, which worked until an tar exited with an error code, in which case the two lines would be reversed. I am unsure how to proceed, as detecting that bash has returned to the user should be a relatively easy task.
Thanks for your help!
If this represents the way you have been trying to match output, it's your problem:
while(reader.readLine() != "\u001B") {}
Except in special cases, you have to use the equals() method on String instances:
while (true) {
String line = reader.readLine();
if ((line == null) || "\u001B".equals(line))
break;
}
I'm not sure why you expect ESC and a newline when a process exits though.
I believe you need to call the Process.waitFor() method.
So you need something like:
Process p = build.start();
p.waitFor()
If you are trying to simulate a bash shell, allowing input of a command, executing, and processing output without terminating. There is an open source project that may be a good reference for code on how to do this. It is available on Git. Take a look at the Jediterm Pure Java Emulator.
Thinking about simulating a bash, I also found this example for Piping between processes also be be relevant.
It does show how to extract the output of a process executing and piping that data as the input into another Java Process. Should be helpful.
I am trying to call a bat file from my Java function. Looks like some issue in the way I am calling the bat file. The batch file is not called from the method. Any help would be appreciated.
private static void Run_Main() throws InterruptedException, SQLException, IOException {
int set_value=0;
while ((set_value=Find_Flag()) !=0){
System.out.println("Set_Value"+set_value);
System.out.println("Staging load is not completed ..Revisiting after 15 minutes....");
Thread.sleep(900000);
set_value=Find_Flag();
}
System.out.println("Staging load is Completed and launching Proudction Load now");
//Runtime.getRuntime().exec(new String[] { "cmd.exe", "/c", "C:/exec/DW_Init_Load.bat" } );
String filePath = "C:/exec/DW_Init_Load.bat";
try {
Process p = Runtime.getRuntime().exec(filePath);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Production Load is finished");
}
I am interested to know what is the mistake I have made in the code
Adding p.waitFor() helped me solve this issues. Initially the block is not waiting for the process to complete.
When my Java program is halted abnormally, applications started by Runtime.exec() do not stop. How do I stop these applications?
Process process = null;
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable()
{
public void run() {
process.destroy();
}
}));
try
{
process = Runtime.getRuntime().exec("win.exe");
process.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
process.destroy();
}
addShutdownHook does not execute on forced shutdown of Java such as:
killing from Task Manager
killing via Eclipse Stop button
kill -9 on Linux.
It does execute when using
Ctrl+c
other user initiated interruptions such as Windows shutdown.
kill on Linux
You can test this by compiling your Java file into a class file, then running on the command line. After running on the command line, you can press Ctrl+c to observe that the shutdown hook is executed.
To test, create RunTimeTest.java as shown below, then compile using your JDK.
For example:
"c:\Program Files\Java\jdk1.7.0_40\bin"\javac RunTimeTest.java
"c:\Program Files\Java\jdk1.7.0_40\bin"\java RunTimeTest
Test code:
import java.io.IOException;
import java.util.Arrays;
public class RunTimeTest {
public static void main(String arguments[]) {
ProcessBuilder processBuilder = new ProcessBuilder(Arrays.asList("notepad.exe"));
Process process = null;
try {
process = processBuilder.start();
final Process processToKill = process;
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Shutdown Hook");
processToKill.destroy();
}
}));
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
if (process != null) {
System.out.println("End of try");
process.destroy();
}
}
}
}
See Javadoc for Runtime
Worst case scenario: if you are using the program multiple times, in the next run you can kill that process.
String command = "cmd /c taskkill /f /im win.exe";
Runtime.getRuntime().exec(command);
I am trying to run reg files with Java. I tried this with no luck:
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
public class RegEdit {
public static void main(String[] args) throws IOException {
// Desktop.getDesktop().open(new File("ihindi.reg"));
String[] cmd = {"regedit", "ihindi.reg"};
Process p = Runtime.getRuntime().exec(cmd);
try {
p.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ihindi.reg
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Control Panel]
"HomePage"=dword:00000001
When I run it, it doesn't make anything and errors. Where am I doing wrong ?
I think you would need to add the "/s" statement in between, your process probably got disturb while you're writing the data into the regedit.
I was in the exactly same situation as yours, no error, but it just couldn't write into the regedit. the "/s" did the job.
try{
// silence all the process without prompting the dialog box to ask if user wanna proceed.
String[] cmd = { "regedit.exe", "/s", regFilePath};
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
}catch (InterruptedException e){
System.out.println(e);
}
There are all sorts of problems with this. The following line:
String[] cmd = {"regedit", "ihindi.reg"};
should pass the full path to the ihindi.reg file, not just the file name.
Also,
It is possible that a dialog box is preventing that waitFor() call from ever returning.
You should call regedit with the /s switch to silence those dialog boxes.
Also, you might consider using a ProcessBuilder like so:
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
public class RegEdit {
public static void main(String[] args) throws IOException {
// Desktop.getDesktop().open(new File("ihindi.reg"));
//you will need to figure this out
String ihindiPath = getIhindiPath();
ProcessBuilder processBuilder = new ProcessBuilder("regedit", "/s", ihindiPath)
try {
processBuilder.start().waitFor();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I think the problem is your paths, with your current code *.reg would have to be in the same directory as the jar file. You can however set the working directory explictly when usong ProcessBuilder:
ProcessBuilder pb = new ProcessBuilder("regedit", "myreg.reg");
pb.directory("c:/");//thus our file should be located in c:\myreg.reg
Process p = pb.start();
This can achieved through Process Builder in JAVA. Please consider the following example for this:
ProcessBuilder processBuilder = new ProcessBuilder("regedit", "reg_file_to_run.reg");
Process processToExecute = processBuilder.start();
And then you can optionally wait for the completion of process execution with this line:
processToExecute.waitFor();
Note: If command in your registry file asks for confirmation prompts while making changes in registry entries, you can perform it silently as well with '/s' option. Like this:
ProcessBuilder processBuilder = new ProcessBuilder("regedit", "/s", "reg_file_to_run.reg");
Withthis command would be executed silently without any confirmation prompt.