• Post Reply Bookmark Topic Watch Topic
  • New Topic

A doubt about Runtime.exec() implementation and command input to programs through it  RSS feed

 
Rafael Campos Cruz
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi everyone!

I come here botter you guys a little because I've been bashing my head on this problem since monday and I've tried my best to grasp everything here but I still can't make it work.
I also based my code on this simple "how to stuff" which makes sense, but I don't know if it is right or not.

Anyhow, my problem: I have a webApplication and I need to call a software installed on my server (Octave) in order to run a mathematical model inside it (it's quite good and fast on doing so). However this software has no java-interface, so the only way to call it is through
calling it using runtime and I NEED to pass instructions for it. Because of the way that Runtime.exec() works the only way to do so would be to input instructions while the software is running.

I was able to understand correctly how to call the software, but I simply can't input commands into it. I know that the command String IS RIGHT, however I think that it don't get to the application correctly... can you guys help me? Here follows the code:



Can you guys help me?
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You need to read the When Runtime.exec() won't article again and look at how it is reading the input and error streams.
The program you are executing may well be outputting some errors which will give you a clue as to why it's not working, but you are ignoring them.
 
Rafael Campos Cruz
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I really tried to, however, if I try to read the OutputStream I'm able to, however the application never exits the "while", follows an example:




And no: No error is returned. Using the example in "When Runtime().exec() won't" it can run Octave correctly (the program being called), with no problem at all.

I believe it's looping for ever because Octave is waiting for a response and, thus, it stays open, waiting, never being terminated. Could you give me some guidelines, or an example, on how to input to this program direct inputs?

P.S.: Another note:

I could run this line, and achieve my objectives, on windows without any problem at all:



halp ><
 
William Brogden
Author and all-around good cowpoke
Rancher
Posts: 13078
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Go back and read that reference again. Also read the JavaDocs for Process.

Consider - suppose something has been written to the error stream - like an error message.

This kind of programming really needs a thread for each stream. Yes that is a pain to program but so it goes.

Bill
 
Paul Clapham
Sheriff
Posts: 22813
43
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Or perhaps rewriting the code to use a ProcessBuilder instead of Runtime.exec() would make that article unnecessary? I suggest that since ProcessBuilder has been in Java since Java 5 (i.e. 2004 if I'm not mistaken), people should be allowed to use it now.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rafael Campos Cruz wrote:I believe it's looping for ever because Octave is waiting for a response

Exactly. That's why if you look at the article again you will see that the inputStream and errorStream are being read in their own threads. You need to do the same.

I suspect that in your original code you were writing the commans too quickly, before Octave was ready to receive them.
As it says in the documentation
Octave displays an initial message and then a prompt indicating it is ready to accept input.
Once you have your threads set up you will need to wait until you see this message and prompt on the inputStream before you write anything to the outputStream
 
Rob Spoor
Sheriff
Posts: 21131
87
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clapham wrote:Or perhaps rewriting the code to use a ProcessBuilder instead of Runtime.exec() would make that article unnecessary?

Partly. ProcessBuilder allows you to redirect the error stream to the output stream, so only one stream needs to be read. There is no need for separate threads that way. But if you don't explicitly setup the redirection, there are still two streams that need to be read concurrently.
 
Rafael Campos Cruz
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, finally managed to understand and solve the problem.

Yes, threads are a necessity in this case, though I still don't understand quite well why (maybe JVM standard?), anyhow, I solved the problem by first creating a classe to handle both command execution and stream printing.

For anyone faces the same issue here it's the code:



With this I implemented 2 methods to automate its calling:



And them I implemented it this way:



The thread.sleep() values are completely arbitrary, as it sort of is what Octave takes to run the mathematical model, so you should fix it to whatever you need.

I would like to point aswell that this is running on a webService inside a ApplicationScopped managed bean, so I could reference my server locally (it's part of a SessionControl that I created, so the server would have to support only 10 running simulations at a time).

Thanks to all on guiding me to the solution!
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rafael, please take the following in the way it's intended - as constructive criticism that will encourage you to learn more about threads, so that you can look at this code again in a few months time and realise just how horrible it is.

Rafael Campos Cruz wrote:Yes, threads are a necessity in this case, though I still don't understand quite well why (maybe JVM standard?)

Threads are a tricky topic but they are something you need to understand. The Java tutorial is probably a good place to start.

Rafael Campos Cruz wrote:

I'm afraid this code is just the same as your original code, but just running in a separate thread.
The loop on line 5 will continue until the inputStream closes. Unfortunately this will not happen until your process completes which will be after you post the exit command later.
Hence lines 8 - 11 will not execute until the process has finished so you will not see any errors that are produced by any of the commands.
Also the loop on line 5 is actually just writing everything the Process outputs back to the Process. This means the initial message and prompt and then any output from the commands you run later.
So basically this thread does nothing other than read the output from the process and write it straight back to the process.

Rafael Campos Cruz wrote:
This is a minor point but it is considered better practice to implement Runnable rather than extend Thread. The tutorial I linked to above explains why.

Rafael Campos Cruz wrote:
All this code does is create a thread, which writes the command to the Process and then exits. The main thread then sleeps for 2 seconds. There is absolutely no point to creating the thread here.
You could have just writtenand it would have worked exactly the same.

Rafael Campos Cruz wrote:The thread.sleep() values are completely arbitrary

And completely unnecessary. You could have implemented a much better solution by checking the output of the Process.

Let me see if I can rewrite this for you to give you something to compare it against.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
First attempt. This still includes the artificial delays. I don't have a copy of Octave to test this on, so have left out the checking of the process output.

Rafael - if you provide me with the output from this, I may be able to improve it.

OctaveRunner.java - you will need to add code to set the value of the actingFolder variable


StreamHandler.java


CommandWriter.java
 
Rafael Campos Cruz
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I changed some stuff according to what you instructed and it simply can't run as being a "Runnable" instead of "Thread", so I kept it as Thread.

The output is the following, which is correct:

[SPOILER]

[/SPOILER]


And here follows my new implementations:





Thanks for the support, as soon as I get time I'll read the guide.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rafael Campos Cruz wrote:I changed some stuff according to what you instructed and it simply can't run as being a "Runnable" instead of "Thread", so I kept it as Thread.

Anything that can be done by extending Thread can be done by implementing Runnable. The only small difference is how you instantiate them. This is explained in the tutorial.

Rafael Campos Cruz wrote:The output is the following, which is correct:

I'm afraid that's more by luck than judgement. You are creating a separate thread for each command you pass to Octave and running those threads at the same time. It's quite possible that those commands could be run in any order.
 
Rafael Campos Cruz
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Joanne Neal wrote:
Rafael Campos Cruz wrote:
I'm afraid that's more by luck than judgement. You are creating a separate thread for each command you pass to Octave and running those threads at the same time. It's quite possible that those commands could be run in any order.


OOooooh, now I understoo what you meant!

So basically:

 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rafael Campos Cruz wrote:So basically:


That'll work, but you only need to create the PrintWriter once. Create it before the first call to runCmd and pass it as a parameter instead of the Process instance.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!