I am currently working on an application that is meant to start and stop different software applications independent of their implementation. Therefore, executable Files are added through simple Drag and Drop and executed on Buttonpress.
I already tried different approaches in Java such as Desktop.open(), Runtime.exec(), using ProcessBuilder or Apache Default Executor. While these approaches work fine for the most part, it seems that OpenRefine would neither open up with the OpenRefine.exe nor with the OpenRefine.bat file. Each time I click the button, nothing happends. I already checked if the execution through doubleclick or commandline works, but for some strange reason I can't get it running in Java. Do you have any additional suggestions to what I can try or what might be the issue with this specific application?
Here is a short sample for the ProcessBuilder Approach
ProcessBuilder processBuilder = new ProcessBuilder(String.valueOf(toolPath));
final Process process = processBuilder.start();
App.globalLogger.info("Started Tool with Process Builder");
InputStream inputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
Where toolPath is respectively the java.nio.file.Path of the File that I imported.
Related
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.
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.
I have a Java program that uses Process Builder to start an external program.
I have a Process Builder with the command, and I use the code below to get the program going.
What I want to do is to print out the output just as the external program would have done, and I try to do this with the following code:
pb.redirectErrorStream(true);
p = pb.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new inputStreamReader(is);
BufferedReader br = new BufferedReader(isr, 32);
while((line = br.readLine()) != null){
System.out.println(line);
}
The problem is that my program is all silent until the external program ends, when suddenly all output comes at once. Or it might not have benn silent if there had been more output, but I want it to produce the output as it comes, ie unbuffered.
The (to me) obvious problem is the BufferedReader and the size of its buffer, but the thing is that I've tried to have a really small buffer, to no avail.
I've also tried to avoid the BufferedReader, and work with the InputStreamReader directly instead, but thet bahaves the same way.
Anyone here that can understand my problem, and perhaps have a solution?
This is caused by buffering in the executed program, not by Java. Nothing you can do about it from the Java end.
This could help
Get Java Runtime Process running in background
run a thread when reading the output of an external application
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.
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.