interacting with console app using java - java

i want to open an external app using java.
Process p = Runtime.getRuntime().exec("/Users/kausar/myApp");
this runs the process as i can see in activity monitor.
Now the file i run is actually console app which then takes commands and gives response based on those commands.
for example if i go to terminal and put the same
Kausars-MacBook-Air:~ kausar$ /Users/kausar/myApp
myApp>
Now i can give commands to app as for example
myApp> SHOW 'Hi There'
These are commands taken as keyboard input in the console app, these are not parameters. I have seen different approaches with parameters. I tried the following as well but couldnt get it to work.
String res;
String cmnd = "SHOW \'Hi There\'";
OutputStream stdin = null;
InputStream stdout = null;
stdout = p.getInputStream();
stdin = p.getOutputStream();
stdin.write(cmnd.getBytes());
stdin.flush();
p.waitFor();
BufferedReader input = new BufferedReader(
new InputStreamReader(stdout));
while ((res = input.readLine()) != null) {
System.out.println(res)
}
input.close();
p.destroy();
Its displaying nothing while the same procedure with "/bin/bash -c ls" works just fine.
please help!

Of hand I would say the problem is with p.*wait*For()
Exactly what object and when to usee notify() or notifyAll() call to wake up the object thread would be something like on stdout and maybe a restructure of the process.
note: an interesting feature is the class field in BufferedReader called "lock", the api docs do mention some way of structuring your program so it can be notified.

Related

Reading from BufferedReader

I am trying to execute commands on the terminal. using
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
reader = new BufferedReader(new InputStreamReader(stdout));
writer = new BufferedWriter(new OutputStreamWriter(stdin));
I am going to use this reader and and writer to continuously communicate with the process.
I'm using the following loop to read
while ((line = reader.readLine()) != null) {
System.out.println("line);
}
ISSUE: The problem here is that, when the reader starts reading from the buffer its forever in the while loop. It never exits.
I tried to put the reading in a thread
public void run() {
try {
String line;
outputText = "";
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ex) {
Logger.getLogger(ThreadReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
But now i have no control on when the reader starts and finishes reading.
GOAL: I need to execute a command and read the output and then the next command.
Your Java program is communicating with an external interactive process. It has only the process's output and error streams to work with to determine how to proceed from any given point. If you want it to recognize subdivisions of the output, such as responses to individual commands, then you need to teach it what the boundaries of those subdivisions look like.
There are any number of ways you might approach the problem. For example, if the external program emits a prompt when it is ready to accept a new command, then it seems natural to watch for that prompt. Alternatively, perhaps you can tweak the input to the program so as to cause it to produce a recognizable marker at the end of each command's output.
Do also consider that this is a solved problem (many times over). The canonical utility for general-purpose scripting of interactive programs is a Tcl program called "Expect". It has inspired work-alikes in many languages, including many in Java. Google gives me three distinct examples among the first five hits, but I have no specific experience with any of them so I make no recommendation.

Java ProcessBuilder: capture output from scripts run from scripts run from Java

Using Java's ProcessBuilder, I can run an external script, and redirect its output into my GUI.
Process proc = pb.start();
BufferedReader bri = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while (proc.isAlive())
{
// bri may be empty or incomplete.
while ((line = bri.readLine()) != null)
{
textArea.appendText(line);
}
}
Now, the script I am running also calls other scripts and processes. Two of these, that should be captured, are currently displayed in their own xterm windows. Is it possible to also capture these outputs, and display in a similar manner?.
If these outputs are being managed by your source script, I think it will work. Just as an advice, take a look in this article: When Runtime.exec() won't
It is extremammly important to read it to learn how to work with external processes correctly.

Java: Redirecting inner process output when running from command line

I use the following code, for redirecting the output of a process I launch from my Java app:
ProcessBuilder builder = new ProcessBuilder("MyProcess.exe");
builder.redirectOutput(Redirect.INHERIT);
builder.redirectErrorStream(true);
Now, this works fine when I run the code from eclipse - I can see the output in Eclipse's console.
Yet when I create a jar file and run it from a cmd window, e.g. java -jar MyJar.jar, it doesn't print the output of the process. What could be the reason for this?
I know I'm late in answering, but I came across this question before coming across the answer, and wanted to save anybody else in the same boat some searching.
This is actually a known bug for Windows: https://bugs.openjdk.java.net/browse/JDK-8023130
You can get around it by redirecting the streams yourself:
Process p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
br.close();
It may be, that process is printing an error and exiting for some reason. So, the actual output goes into Err stream and not into the Out stream. Your code redirects Out stream only, so important process error information may be lost. I would suggest to inherit both Out and Err streams using this code:
ProcessBuilder builder = new ProcessBuilder("MyProcess.exe");
builder.inheritIO();
One more reason to redirect both streams is related to the output buffering for child process. If parent process (your java application) is not reading or redirecting standard streams (Out and Err) of the child process, then the latter may be blocked after a while, unable to make any further progress.
It definitely wouldn't hurt to have possible errors in the output anyway.

ProcessBuilder running processes in foreground

I want to run an executable written in C++ and to see the cmd promt associated with it in foreground, since the executable prints some lines in the cmd.
I have written the following code, but all processes are created and run in background (In this code I open the dummy cmd.exe process, not my process).
Process p = new ProcessBuilder("C:\\Windows\\System32\\cmd.exe").start();
How can i enable foreground running of processes?
Thanks!
The issue is not whether the process is in the foreground or background. When you start a process using Java, you have to use Java to control that process' lifecyle. The Java API provides you access to various attributes of the process. What you're interested in here is the output of the process. That is represented by the process' InputStream. It seems counterintuitive, but it makes sense because from the perspective of your Java program, the process' output is the program's input. Conversely, if you need to send data to the process, you write to the process' OutputStream.
To sum up, access the process' InputStream and print that out to the command-line:
Process process = new ProcessBuilder("C:\\Path\\To\\My\\Application.exe").start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line);
}
System.out.println(line);
This code, of course, assumes that your process is not waiting for any input, i.e., it is not interactive.
Vivin Paliath's answer is really the way to go, then you can do whatever you want with the output, display it in your own dialogue, log it, interpret it, check for errors or whatever.
But just in case you really want that command window showing up. Execute cmd.exe and get the process' OutputStream and write the command (application.exe) to it ending with a new line.
Something along the lines of:
Process p = new ProcessBuilder("C:\\Windows\\System32\\cmd.exe").start();
out = p.getOutputStream();
out.write("path\\application.exe\r\n".getBytes());
out.flush();
Should usually drain the input stream too though anyway.

Can't launch external program from Java without closing java app

I'm trying to launch an external program from my java swing app using this:
Process proc = Runtime.getRuntime().exec(cmd);
But the external program never actually gets launched until I close out of my java app...everytime.
It waits to launch only after I have closed out.
the external program I am trying to run is an exe that takes arguments so:
cmd = "externalProgram.exe -v --fullscreen --nowing";
What could possibly be wrong here.
Funny enough it works as expected if i try something simple like:
Process proc = Runtime.getRuntime().exec("notepad.exe");
You may need to read from the process's standard output, or close the standard input, before it will proceed. For reading the output, the problem is that the buffer can get full, blocking the program; for closing the input, the problem is that some programs will try to read data from there if it's available, waiting to do so. One or both of these tricks is very likely to straighten things out for you.
You may also read the error output stream to check it the program is actually being unsuccessfully executed
String cmd = "svn.exe";
Process proc = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
reader.close();
My console shows
Type 'svn help' for usage.
Which evidently shows the program was executed by Java.

Categories

Resources