Interacting with another process Java - java

I am trying to interact with another process in Java. It goes like this...
Runtime rt;
Process pr=rt.exec("cmd");
then I send some commands to the process using...
BufferedReader processOutput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(pr.getOutputStream()));
processInput.write("gdb");
processInput.flush();
I don't care about the output for now.. so I try to ignore it using..
while(processOutput.readLine() != null);
but this loops hangs forever. I know this is because process is still running and doesn't sends a null. I don't want to terminate it now. I have to send commands based on user Input and then get the output..
How to do this? In other words I want to flush the Process output stream or ignore it after executing some commands and read it only when I want to.

Use a separate thread to read the output. This way, as long as there is output it will be read, but will not block you.
For example, create such a class:
public class ReaderThread extends Thread {
private BufferedReader reader = null;
public ReaderThread(BufferedReader reader) {
this.reader = reader;
}
#Override
public void run() {
String line = null;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
catch(IOException exception) {
System.out.println("!!Error: " + exception.getMessage());
}
}
}
And in your main class, instead of while(processOutput.readLine() != null);, call:
ReaderThread reader = new ReaderThread(processOutput);
reader.start();

Related

how to properly close ssh connection / session here?

I have a client/server socket program.
Server part is connecting via ssh to a host, runs a script, and sends each line of the output to the client.
The below server code part returns a BufferedReader containing the script output as it happens:
public synchronized BufferedReader runScript(<params>) {
BufferedReader br = null ;
try {
Connection conn = new Connection(host);
conn.connect();
... // authentication part
Session sess = conn.openSession();
sess.execCommand("ascript");
InputStream stdout = new StreamGobbler(sess.getStdout());
br = new BufferedReader(new InputStreamReader(stdout));
} catch (Exception e) {
e.printStackTrace();
}
return br;
}
The above method is called from another server-side class/code as below, writing each line of the BufferedReader to the client through a socket, so that client sees the live output of the script as it runs :
BufferedReader br = new UnixCommandExecutor().runScript(<params>);
String line;
while ((line = br.readLine()) != null) {
out.writeObject(line);
}
The obvious problem with runScript method is that it doesn't close the ssh Connection & Session (ganymed ssh lib), as it instantly returns the BufferedReader (if I'm not mistaken) while the underlying script still runs . If I close these before the return statement, the BufferedReader would be incomplete.
So how do I properly close connection/session here as soon as the underlying script completes ?
(I'm aware of try-with-resources and will use it, however I doubt it will solve the problem completely?)
I would suggest that you refactor the code, so that you
either wrap the parts into an object and handling the close operation later
or you consume the Reader immediately and close the connection after you are done with it.
Do not pass the Reader to the outside without maintaining the connection.
Below a somewhat simplified example on how it could be done.
If you need to process through mutliple steps before your are done with the Reader, you might not be able to wrap the ResultHandler in a try { ... } catch block. In that case you need a different meachnism to ensure that this will eventually be closed.
But judging from your problem description that might not be the case.
If you do not want to block till the operation is done (anyway this operation is something that should be executed in a background thread), then you probably want to send each output line you receive to somewhere where it can be displayed. In this case you can should provide an interface that you use to forward the received lines.
While the reader still receives output (as long as the input stream / connection is active) you`ll probably need to loop. Somehow you need to figure out when your operation is completed.
For example your script could close the connection (from the serverside) once it is done or return something specific to you that you can interpret as end of operations.
public class ResultHandler {
String host;
Connection conn;
BufferedReader reader = null;
public ResultReader(String host) {
this.host = host;
}
public void connect(<params>) throws Exception {
// if you intend to reuse the object, just check that it was properly cleanedup before
close();
conn = new Connection(host);
conn.connect();
... // authentication part
// you might want to move the actual handling to a different method
Session sess = conn.openSession();
sess.execCommand("ascript");
InputStream stdout = new StreamGobbler(sess.getStdout());
br = new BufferedReader(new InputStreamReader(stdout));
}
public BufferedReader getReader() {
return this.reader;
}
public void close() {
If (reader != null) {
reader.close();
}
if (conn != null) {
conn.close();
}
}
public void finalize() {
close();
}
}
synchronized void runScript(<params>) {
ResultHandler handler;
try {
handler = new ResultHandler(host);
handler.connect();
// consume the reader for whatever you need to do
} catch (Exception e) {
e.printStackTrace();
} finally {
// or use try-with-resource and implement the proper interface for that
if (handler != null) {
handler.close();
}
}
}

Spring Boot started from Runtime.getRuntime().exec() keep waiting until the caller process gets terminated

I Have two spring boot applications, one is called ProcessCenter, that is an API for some mobile and desktop applications, and the other one is called Watcher, responsible for keep everything running.
My problem:
When the Watcher see that ProcessCenter is closed, he calls Runtime.getRuntime().exec( "java -jar ProcessCenter.jar" ), then the ProcessCenter begin to start, but freezes, i got no error, no log, nothing, just keep freeze, until the Watcher is closed, then it resume starting and works just fine
Help anyone?
Based on the JDK's Javadoc documentation: "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."
You can follow this article that can help you out how to implement an external process call corrrectly, helping you to manage the buffer -> https://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2
To summarize, you can create a class that can manage the buffer limitations, processing the output of your program no matter how big it is. An example:
import java.util.*;
import java.io.*;
class StreamGobbler extends Thread
{
InputStream is;
String type;
OutputStream os;
StreamGobbler(InputStream is, String type)
{
this(is, type, null);
}
StreamGobbler(InputStream is, String type, OutputStream redirect)
{
this.is = is;
this.type = type;
this.os = redirect;
}
public void run()
{
try
{
PrintWriter pw = null;
if (os != null)
pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
{
if (pw != null)
pw.println(line);
System.out.println(type + ">" + line);
}
if (pw != null)
pw.flush();
} catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
public class GoodWinRedirect
{
public static void main(String args[])
{
if (args.length < 1)
{
System.out.println("USAGE java GoodWinRedirect <outputfile>");
System.exit(1);
}
try
{
FileOutputStream fos = new FileOutputStream(args[0]);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("java jecho 'Hello World'");
// any error message?
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERROR");
// any output?
StreamGobbler outputGobbler = new
StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
fos.flush();
fos.close();
} catch (Throwable t)
{
t.printStackTrace();
}
}
}

Executing 'adb logcat' command using Runtime class

I was trying to get the logcat content into a JTextPane. I used following code hoping it will return the content as String but it freeze and also, doesn't produce an error.
Process exec = null;
try {
exec = Runtime.getRuntime().exec("adb logcat -d");
InputStream errorStream = exec.getErrorStream();
BufferedReader ebr = new BufferedReader(new InputStreamReader(errorStream));
String errorLine;
while ((errorLine = ebr.readLine()) != null) {
System.out.println("[ERROR] :- " + errorLine);
}
if (exec.waitFor() == 0) {
InputStream infoStream = exec.getInputStream();
InputStreamReader isr = new InputStreamReader(infoStream);
BufferedReader ibr = new BufferedReader(isr);
String infoLine;
while ((infoLine = ibr.readLine()) != null) {
System.out.println("[INFO] :- " + infoLine);
}
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
} finally {
if (exec != null) {
exec.destroy();
}
}
I referred to some tutorials but, they were not filling my problem. Is this wrong? Are there any other methods to get the logcat content as a String programmatically? Sorry if this is a dumb question.
The issue you're seeing is that you're trying to process command streams and wait for the executing process, all in the same thread. It's blocking because the process reading the streams is waiting on the process and you're losing the stream input.
What you'll want to do is implement the function that reads/processes the command output (input stream) in another thread and kick off that thread when you start the process.
Second, you'll probably want to use ProcessBuilder rather than Runtime.exec.
Something like this can be adapted to do what you want:
public class Test {
public static void main(String[] args) throws Exception {
String startDir = System.getProperty("user.dir"); // start in current dir (change if needed)
ProcessBuilder pb = new ProcessBuilder("adb","logcat","-d");
pb.directory(new File(startDir)); // start directory
pb.redirectErrorStream(true); // redirect the error stream to stdout
Process p = pb.start(); // start the process
// start a new thread to handle the stream input
new Thread(new ProcessTestRunnable(p)).start();
p.waitFor(); // wait if needed
}
// mimics stream gobbler, but allows user to process the result
static class ProcessTestRunnable implements Runnable {
Process p;
BufferedReader br;
ProcessTestRunnable(Process p) {
this.p = p;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(p.getInputStream());
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
// do something with the output here...
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}

Read input from Runtime().exec with Non-block I/O

It seems that using BufferedReader to read a process's InputStream
will somehow result in a block I/O behavior.
And the effect is like the program doesn't get the instant input from the process.
I know there are more lines that could be read at that time, but the BufferedReader
just keep waiting for sometime then I can finally get the lines updated.
Here is the code:
While((str=bufferedReader.readLine()!=null) {
System.out.println(str);
}
Is there some kinds of method that can keep reading from the process without blocking
in the while() condition? cause the process won't return null or anything....
You can read the child process output in a separate thread. Something like this
static BlockingQueue<String> queue = new LinkedBlockingDeque<>();
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec("cmd /c dir");
final BufferedReader rdr = new BufferedReader(new InputStreamReader(p.getInputStream()));
Thread t = new Thread() {
public void run() {
try {
for (String line; (line = rdr.readLine()) != null;) {
queue.put(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
for (;;) {
String line = queue.poll();
if (line != null) {
System.out.println(line);
} else if (!t.isAlive()) {
break;
}
}
}
You can use the NuProcess library for non-blocking I/O to external processes. Consider it a replacement for ProcessBuilder and Process in Java.

How to send output messages from a .exe program with Java?

Here is the situation:
I have a java application which executes another java application example.exe (example.exe has some System.out.println("...");)
I want to get the output Stream from example.exe so i tried with something like that:
(looks pretty standard)
final Process process = Runtime.getRuntime().exec("example.exe");
new Thread() {
public void run() {
try {
BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
try {
while((line = inputReader.readLine()) != null) {
inputText = inputText + line;
}
System.out.println(inputText);
} finally {
inputReader.close();
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}.start();
I would like to get the output messages of example.exe but it doesn't work and i don"t understand why, i get one message but not the one from example.exe, probably from java or something else.

Categories

Resources