Error/Output streams with current java process - java

I know to use ErrorStream or OutputStream you do the following
Process process = Runtime.getRuntime ().exec ("the command you want to execute");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
What if I don't want to start a new process, I want to get the ErrorStream & OutputStream of the current application I am working on. (The current process).
How to get it ?

You use System.out and System.err.

Related

Send command to running process

is it possible to send a command to an running Process like in the example below?
And how would you do that?
Process p = pb.start();
Most possibly not what you are wanting to achieve, but yes, you can communicate to a running Process with Process.getOutputStream()
For processes that read and write to the command line use p.getOutputStream() to send data to the process and p.getIntputStream() to read data from the process. For GUI processes you need native code to send messages depending on the operating system.
Edit:
Example code for processes that are reading/writing to the console:
Process process = pb.start();
// process stdout
Scanner stdout = new Scanner(
new BufferedReader(
new InputStreamReader(process.getOutputStream())));
// process stdin
PrintWriter stdin = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(process.getInputStream())), true);
// sending commands to the process
stdin.println("command1");
stdin.println("command2");
stdin.println("command3");
// reading process output
while (stdout.hasNextLine()) {
System.out.println("Process output: " + stdout.nextLine());
}

Java Processbuilder Stream to Python-Script

I have a minor Problem with a small Project I'm trying to do.
I'm trying to use a Java-Program to call a Python-Script.
Java:
ProcessBuilder pb = new ProcessBuilder("python3", "tmp.py");
process = pb.start();
OutputStream stdin = process.getOutputStream();
InputStream stderr = process.getErrorStream();
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
writer.write("example" + "\n");
String output = reader.readLine();
Python-Script tmp.py (example):
import sys
sys.stdin.readline()
print("Hello World")
It wont terminate, seemingly because sys.sdin.readline() isnt catching any input and if I remove this line it terminates just fine.
(stderror was empty too)
I tried different things to fix this but nothing seems to work.
I would really appreciate any advice. Thanks in advance.
(Update: I tried to modify the Java-Program to access a .jar File instead of a Python-Script but the same error occurs here to. Using the Python Method subprocess.Popen() to access the Script however works just fine.)
Make sure you start python unbuffered with -u flag:
Force the binary layer of the stdout and stderr streams (which is
available as their buffer attribute) to be unbuffered. The text I/O
layer will still be line-buffered if writing to the console, or
block-buffered if redirected to a non-interactive file.
Edit
I recommend reviewing the buffering all the same. The python unbuffered is a common one, but you possibly still have some buffering. Make sure you flush java writer, writer.flush().

IOUtils.copy() hangs when copying big stream?

I want to parse content of some file by srcML parser which is an external windows program. I'm doing this in a following way:
String command = "src2srcml.exe --language java";
Process proc = Runtime.getRuntime().exec(command);
InputStream fileInput = Files.newInputStream(file)
OutputStream procOutput = proc.getOutputStream();
IOUtils.copy(fileInput, procOutput);
IOUtils.copy() is from Commons IO 2.4 library.
When my file is small (several KB) everything works fine. However, when I try to copy some relatively big file (~72 KB) my program hangs.
Moreover, when I execute the parser 'manually' in cmd:
src2srcml.exe --language Java < BigFile.java
everything works fine, too.
Any ideas why this is happening?
You should buffer the OutputStream:
OutputStream procOutput = proc.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(procOutput);
IOUtils.copy(fileInput, bos);
Moreover, why don't you simply redirect fileInput as the process InputStream?
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectInput(file);
Process proc = pb.start();
proc.waitFor();
The problem is most likely that you are not consuming the output of the external program in a separate thread. you need to start a separate thread to consume the output so that the external program does not get blocked.

How to write in Java to stdin of ssh?

Everything works fine on the command line, but when I translate what I want into Java, the receiving process never gets anything on stdin.
Here's what I have:
private void deployWarFile(File warFile, String instanceId) throws IOException, InterruptedException {
Runtime runtime = Runtime.getRuntime();
// FIXME(nyap): Use Jsch.
Process deployWarFile = runtime.exec(new String[]{
"ssh",
"gateway",
"/path/to/count-the-bytes"});
OutputStream deployWarFileStdin = deployWarFile.getOutputStream();
InputStream deployWarFileStdout = new BufferedInputStream(deployWarFile.getInputStream());
InputStream warFileInputStream = new FileInputStream(warFile);
IOUtils.copy(warFileInputStream, deployWarFileStdin);
IOUtils.copy(deployWarFileStdout, System.out);
warFileInputStream.close();
deployWarFileStdout.close();
deployWarFileStdin.close();
int status = deployWarFile.waitFor();
System.out.println("************ Deployed with status " + status + " file handles. ************");
}
The script 'count-the-bytes' is simply:
#!/bin/bash
echo "************ counting stdin bytes ************"
wc -c
echo "************ counted stdin bytes ************"
The output indicates that the function hangs at the 'wc -c' line -- it never gets to the 'counted stdin bytes' line.
What's going on? Would using Jsch help?
You might try closing the output stream before you expect wc -c to return.
IOUtils.copy(warFileInputStream, deployWarFileStdin);
deployWarFileStdin.close();
IOUtils.copy(deployWarFileStdout, System.out);
warFileInputStream.close();
deployWarFileStdout.close();
Would using Jsch help?
Using JSch would only help if you would be using the setInputStream() and setOutputStream() methods of the channel instead of the IOUtils.copy method, since they manage the copying on a separate thread.
ChannelExec deployWarFile = (ChannelExec)session.openChannel("exec");
deployWarFile.setCommand("/path/to/count-the-bytes");
deployWarFile.setOutputStream(System.out);
deployWarFile.setInputStream(new BufferedInputStream(new FileInputStream(warFile)));
deployWarFile.connect();
(Here you somehow have to wait until the other side closes the channel.)
If you simply replaced the Runtime.exec with opening an ChannelExec (and starting it after getting the streams), the problem would be completely the same, and could be solved by the same solution mentioned by antlersoft, i.e. closing the input before reading the output:
ChannelExec deployWarFile = (ChannelExec)session.openChannel("exec");
deployWarFile.setCommand("/path/to/count-the-bytes");
OutputStream deployWarFileStdin = deployWarFile.getOutputStream();
InputStream deployWarFileStdout = new BufferedInputStream(deployWarFile.getInputStream());
InputStream warFileInputStream = new FileInputStream(warFile);
deployWarFile.connect();
IOUtils.copy(warFileInputStream, deployWarFileStdin);
deployWarFileStdin.close();
warFileInputStream.close();
IOUtils.copy(deployWarFileStdout, System.out);
deployWarFileStdout.close();
(Of course, if you have longer output, you will want to do input and output in parallel, or simply use the first method.)
You probably get an error, but the process hangs because you are not reading the error stream.
Taken from the Process JavaDoc
All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (Process.getOutputStream(), Process.getInputStream(), Process.getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
So you need to read all of them. Using the ProcessBuilder is probably easier

Call "interactive" Perl script from Java

I want to call an "interactive" Perl script from a Java program. Just for the clarity, the other way around (from Perl to Java) is not good for me.
The script is interactive in the sense that it requires a small configuration dialog with the user. For example, calling the script in cmd.exe would lead to a dialog like:
Do you want to overwrite the old settings? [yes,no (default=no)]
and the user should choose between writing yes, no or nothing at all in the command line.
And depending on the user choice another message would appear: "Do you want to...." and the user will respond etc etc. I think you got the picture.
My question is how can I have the same dialog with the user when the script is called in a Java program? I mean, how can I capture the script's questions to the user, show them to user and then send the user's answer (got in the Java program) to the script?
A simple Runtime.getRuntime().exec() doesn't work in this case.
Hope I expressed clear enough the question.
Thank you for your help!
You must use getInputStream/getOutputStream methods to get access to stdin and stdout of perl stript. You can read and write to these streams to simulate user's behavior
OutputStream stdin = null;
InputStream stderr = null;
InputStream stdout = null;
Process process = Runtime.getRuntime ().exec ("...");
stdin = process.getOutputStream ();
stderr = process.getErrorStream ();
stdout = process.getInputStream ();
// "write" the parms into stdin
String line = "data\n";
stdin.write(line.getBytes());
stdin.flush();
stdin.close();
// clean up if any output in stdout
BufferedReader brCleanUp =
new BufferedReader (new InputStreamReader (stdout));
while ((line = brCleanUp.readLine ()) != null) {
//System.out.println ("[Stdout] " + line);
}
brCleanUp.close();
// clean up if any output in stderr
brCleanUp =
new BufferedReader (new InputStreamReader (stderr));
while ((line = brCleanUp.readLine ()) != null) {
//System.out.println ("[Stderr] " + line);
}
brCleanUp.close();
This is a job for Expect. In Java: ExpectJ, expect4j
If (1) your call is from Java to Perl, and (2) you are not parsing the Perl script itself, why not use a JOptionPane.showConfirmDialog() from the Java code? Shouldn't be a big deal if a Yes/No is all your are getting from the script. Whatever you are printing to display to the user can be included in that confirm dialog as a plain ASCII text, too.

Categories