Create a new process in current console window - java

I have a Java application which for example needs to restart itself (but also needs to start other processes). This is currently done by closing the current application and then start a new instance using a ShutdownHook and a ProcessBuilder.
My problem is now that the new process runs somewhere in the background and does not have its own console window. On windows machines, a new console window can be created using
cmd /c start "windowtitle" java -jar myApp.jar
But this creates 2 processes: the cmd process and the java process started by 'start'. This makes it for example impossible to get the stdout and stderr of the started process, because we only get those streams for the cmd process, not for the one started by the 'start' command.
The very best solution for me would be to reuse the current console window for the new process but this seems somehow impossible to achieve as i did not find any information on how to do this.
Additionally I would appreciate a solution which works on Unix machines.

Seems, you owe to use small console program-starter for java. It must start java and immediately exit.
#include <windows.h>
#include <tchar.h>
int main(int argc, char** argv)
{
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi = {};
CreateProcess(NULL,_T("java -jar myApp.jar"),0,0,0,NORMAL_PRIORITY_CLASS,0,0,&si,&pi);
return 0;
}

I do not know if that's what you're looking for, but it might help.
List<String> command = Arrays.asList("java", "-jar", "myApp.jar");
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream is = process.getInputStream();
final InputStreamReader isr = new InputStreamReader(is);
final BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.getLine()) != null) {
System.out.println("child process: " + line);
}
process.waitFor();
The builder.redirectErrorStream(true); will redirect the stderr to stdout and the while loop will write the stdout of the child process to the stdout of your main application. And don't forget to try catch the Streams and Buffers

Related

java getRuntime().exec() not working?

Basically, when I type these commands in
the terminal by hand, the sift program works and writes a .key file, but when I try to call it from my program, nothing is written.
Am I using the exec() method correctly? I have looked through the API and I can't seem to spot where I went wrong.
public static void main(String[] args) throws IOException, InterruptedException
{
//Task 1: create .key file for the input file
String[] arr = new String[3];
arr[0] = "\"C:/Users/Wesley/Documents/cv/final project/ObjectRecognition/sift/siftWin32.exe\"";
arr[1] = "<\"C:/Users/Wesley/Documents/cv/final project/ObjectRecognition/sift/cover_actual.pgm\"";
arr[2] = ">\"C:/Users/Wesley/Documents/cv/final project/ObjectRecognition/sift/keys/cover_actual.key\"";
String command = (arr[0]+" "+arr[1]+" "+arr[2]);
Process p=Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
while(line!=null)
{
System.out.println(line);
line=reader.readLine();
}
}
The command line you are using is a DOS command line in the format:
prog < input > output
The program itself is executed with no arguments:
prog
However the command from your code is executed as
prog "<" "input" ">" "output"
Possible fixes:
a) Use Java to handle the input and output files
Process process = Runtime.getRuntime().exec(command);
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
// Start a background thread that writes input file into "stdin" stream
...
// Read the results from "stdout" stream
...
See: Unable to read InputStream from Java Process (Runtime.getRuntime().exec() or ProcessBuilder)
b) Use cmd.exe to execute the command as is
cmd.exe /c "prog < input > output"
You can't use redirections (< and >) with Runtime.exec as they are interpreted and executed by the shell. It only works with one executable and its arguments.
Further reading:
https://stackoverflow.com/a/11250789/105224
You cannot use input/output redirection with Runtime.exec. On the other hand, the same method returns a Process object, and you can access its input and output streams.
Process process = Runtime.exec("command here");
// these methods are terribly ill-named:
// getOutputStream returns the process's stdin
// and getInputStream returns the process's stdout
OutputStream stdin = process.getOutputStream();
// write your file in stdin
stdin.write(...);
// now read from stdout
InputStream stdout = process.getInputStream();
stdout.read(...);
I test, it's ok. You can try. Good luck
String cmd = "cmd /c siftWin32 <box.pgm>a.key";
Process process = Runtime.getRuntime().exec(cmd);
*For special characters that usually cause problems:
This code works correctly even with file names like: "1 - Volume 1 (Fronte).jpg"
String strArr[] = {"cmd", "/C", file.getCanonicalPath()};
Process p = rtObj.exec(strArr);///strCmd);
Agree too, redirection not supported here.
Tested on Windows 7
{guscoder:912081574}

Interact with Powershell process called from Java application

I'm trying to run a Java application which creates a new powershell process on startup and then later on interacts with it multiple times. Calling powershell.exe and have it execute a single command and return the output works fine for me. The problem arises if I don't want the powershell process to immediately finish/exit but to stay open so I can write to its outputStream and receive results back from the inputStream.
String input = "dir";
String[] commandList = {"powershell.exe", "-Command", "dir"};
ProcessBuilder pb = new ProcessBuilder(commandList);
Process p = pb.start();
if(input != null) {
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(p.getOutputStream())), true);
writer.println(input);
writer.flush();
writer.close();
}
//p.getOutputStream().close();
Gobbler outGobbler = new Gobbler(p.getInputStream());
Gobbler errGobbler = new Gobbler(p.getErrorStream());
Thread outThread = new Thread(outGobbler);
Thread errThread = new Thread(errGobbler);
outThread.start();
errThread.start();
System.out.println("Waiting for the Gobbler threads to join...");
outThread.join();
errThread.join();
System.out.println("Waiting for the process to exit...");
int exitVal = p.waitFor();
System.out.println("\n****************************");
System.out.println("Command: " + "cmd.exe /c dir");
System.out.println("Exit Value = " + exitVal);
List<String> output = outGobbler.getOuput();
input = "";
for(String o: output) {
input += o;
}
System.out.println("Final Output:");
System.out.println(input);
This code returns the result of the "dir" command from a powershell - fine. But as you can see, I'm trying to run a second "dir" command using
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(p.getOutputStream())), true);
writer.println(input);
writer.flush();
This has no effect whatsoever - no second dir output is shown when I run my code. I've also experimented with a powershell.exe option to open the powershell but not close it immediately:
String[] commandList = {"powershell.exe", "-NoExit", "-Command", "dir"};
But then my code hangs, meaning the Gobbler's who consume the process's inputStream don't read anything - strangely enough: they don't even read the first line - there must be at least some output....
I've also tried to close the process's outputStream after writing the second "dir" command to it - didn't change anything.
Any help is highly appreciated.
Thanks
Kurt
This sounds about right for the nature of a process spun up by another process. I think you're experiencing pretty standard behavior.
This is the key: p.waitFor()
From Java docs:
causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
You won't be able to receive the PowerShell output stream until it has terminated. When you run with -NoExit it never exits which is why you are experiencing the hang.
If you run ProcExp from Sysinternals you'll be able to see your Java process spin up an child PowerShell process.
So I don't think you'll be able to interact with it like it's a live object in memory.

Ctrl C through OutputStreamWriter in Linux

I have a shell script running through a process runtime on Java.
This Shell Script only stops when you hit CTRL+C
Right now I catch the InputStream from the script in a JTextArea.
but I can't send CTRL+C.
When you run CTRL+C on a Shell Konsole the script stops and sends back information.
and this information is the one that I Can't Catch.
So
How can I Send CTRL+C Through Process runtime?
How can I catch the Inputstream from CTRL+C?
File dirw = new File("/home/mydir/sh/");
Runtime runtime = Runtime.getRuntime();
Process process = null;
process = runtime.exec("./start_test.sh", null, dirw);
OutputStream outp = new OutputStream(process.getOutputStream());
InputStreamReader isr = new InputStreamReader(process.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line = null;
int cont = 1;
while ((line = br.readLine()) != null) {
jtextarea.append("LineOK " + line + "\n");
if( cont == 10) {
outp.write(3); //sending Ctrl+C
outp.flush();
cont =0;
}
cont ++;
}
CTRL+C is a command sent from user to shell. When shell receives it, it sends SIGINT to the foreground process.
To do this in Java use Process.sendSignal(pid, Process.SIGNAL_QUIT) - this only works on Android.
Update: the above command is wrong as it's only available on Android.
The correct way is to send kill -2 pid. Beware: this is UNIX-only solution. Another problem is getting the pid (process id). It turns out there is no OS-agnostic solution to it: How to get PID of process I've just started within java program?
The solution is to resort to OS-dependent hacks as mentioned in the link (getting pid from Process via reflection).

Problem ProcessBuilder running script sh

trying to execute an script, using this piece of code:
String command = "./myScript.sh";
pb = new ProcessBuilder(command, param1, param2);
pb.directory(directory);
pb.start();
I am not getting any kind of error, but neither the supposed results. Anyway, I tryed to run the same command, direclty in the terminal, and everything working correctly.
Am I missing something??
Thanks in advance
When you start a process (pb.start()) you get back a Process instance. If your script reads input or writes output to stdout or stderr you need to handle this on separate threads using Process.getInputStream(), ...getOutputStream() and getErrorStream(). If you don't do this the process can hang. You also should call Process.waitFor() and then Process.exitValue() to get the return status of the process. If it's a negative number then the system was unable to launch your script.
EDIT: Here is a short simplified example. This is a toy only and will work reliably ONLY under the following conditions:
The script does not require any input
The script does not produce a large amount of output on both stdout and stderr. If it does, then since the program reads all of stdout before stderr, the stderr buffer may fill up and block the process from completing. In a 'real' implementation you would read stdout and stderr in separate threads (hint, wrap the loadStream() method in a class that implements Runnable).
public class PBTest
{
public static void main(String[] args) throws Exception
{
ProcessBuilder pb = new ProcessBuilder("sc","query","wuauserv");
Process p = pb.start();
String output = loadStream(p.getInputStream());
String error = loadStream(p.getErrorStream());
int rc = p.waitFor();
System.out.println("Process ended with rc=" + rc);
System.out.println("\nStandard Output:\n");
System.out.println(output);
System.out.println("\nStandard Error:\n");
System.out.println(error);
}
private static String loadStream(InputStream s) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(s));
StringBuilder sb = new StringBuilder();
String line;
while((line=br.readLine()) != null)
sb.append(line).append("\n");
return sb.toString();
}
}
The problem was not on the way I called the script, which was right.
But it was inside the script. At first it was:
#!/bin/bash
inputFolder=$1
outputFolder=$2
cd $inputFolder
for file in `ls ` ; do
ffmpeg -i $inputFolder/$file -ar 22050 $outputFolder/$file.mp4
done
But I got ffmpeg command not found, so I changed it to:
#!/bin/bash
inputFolder=$1
outputFolder=$2
cd $inputFolder
for file in `ls ` ; do
/usr/local/bin/ffmpeg -i $inputFolder/$file -ar 22050 $outputFolder/$file.mp4
done
with the hole path. But I have still doubts, why this is necessary, if I have ffmpeg in my path and I cand execute in console direclty form any directory??
If someone can give me an answer, it will be welcome :)

Using Java to call Linux terminal: How to flush the output?

1) I'm using Java to call Linux terminal to run foo.exe and save the output in a file:
String[] cmd = {"/bin/sh", "-c", "foo >haha.file"};
Runtime.getRuntime().exec(cmd);
2) The problem is when I plan to read haha.file later in the code, it hasn't been written yet:
File f=new File("haha.file"); // return true
in = new BufferedReader(new FileReader("haha.file"));
reader=in.readLine();
System.out.println(reader);//return null
3) Only after the program is done will the haha.file be written. I only know how to flush "Writers" but don't know how to flush sth. like this.
How can I force java to write the file in the terminal?
Thanks in advance
E.E.
This problem is caused by the asynchronous nature of Runtime.exec. foo is being executed in a seperate process. You need to call Process.waitFor() to insure the file has been written.
String[] cmd = {"/bin/sh", "-c", "foo >haha.file"};
Process process = Runtime.getRuntime().exec(cmd);
// ....
if (process.waitFor() == 0) {
File f=new File("haha.file");
in = new BufferedReader(new FileReader("haha.file"));
reader=in.readLine();
System.out.println(reader);
} else {
//process did not terminate normally
}
You can either wait for the completion of the process:
Process p = Runtime.getRuntime().exec(cmd);
int result = p.waitFor();
Or use the p.getInputStream() to read directly from the standard output of the process.

Categories