External Applications & Java’s Runtime.exec()

Follow up to the last entry on Java & PGP, I found this article on Java World entitled “When Runtime.exec() won’t” that made a couple of great points. First, in reference to the 2 methods available to developers working with the Process class (waitFor() and exitValue()), he said:

If an external process has not yet completed, the exitValue() method will throw an IllegalThreadStateException; that’s why this program failed. While the documentation states this fact, why can’t this method wait until it can give a valid answer?

A more thorough look at the methods available in the Process class reveals a waitFor() method that does precisely that. In fact, waitFor() also returns the exit value, which means that you would not use exitValue() and waitFor() in conjunction with each other, but rather would choose one or the other. The only possible time you would use exitValue() instead of waitFor() would be when you don’t want your program to block waiting on an external process that may never complete. Instead of using the waitFor() method, I would prefer passing a boolean parameter called waitFor into the exitValue() method to determine whether or not the current thread should wait. A boolean would be more beneficial because exitValue() is a more appropriate name for this method, and it isn’t necessary for two methods to perform the same function under different conditions. Such simple condition discrimination is the domain of an input parameter.

Does the above mean that if you want to execute or invoke a long running external process using Java, you should simply call the exitValue() method on the process immediately after calling Runtime.exec() and then ignore the IllegalThreadStateException exception that gets thrown?

Second, he mentions:

One final pitfall to cover with Runtime.exec() is mistakenly assuming that exec() accepts any String that your command line (or shell) accepts. Runtime.exec() is much more limited and not cross-platform. This pitfall is caused by users attempting to use the exec() method to accept a single String as a command line would. The confusion may be due to the fact that command is the parameter name for the exec() method. Thus, the programmer incorrectly associates the parameter command with anything that he or she can type on a command line, instead of associating it with a single program and its arguments.

The call to the PGP executable I wrote a couple days ago does work, but it could be improved by breaking up the program (pgp.exe) from the arguments (-eatw c:\pgp6.5.8\tempfile.txt aaron.s.johnson@gmail.com) like this:

String[] args = {"c:\\pgp6.5.8\\pgp", "-eatw", "c:\\pgp6.5.8\\tempfile.txt", "aaron.s.johnson@gmail.com"};
Process process = rt.exec(args);

Other links:
Java World: When Runtime.exec() won’t
Mountain Storm:Java’s Runtime.exec() and External Applications

4 thoughts on “External Applications & Java’s Runtime.exec()”

  1. I find the following particularly apt:
    ‘reserve simple APIs for simple operations’.
    So in your first question about executing long running operations, I would use exitValue() and be agnostic to failure.
    If the external activity is complex I’d write a wrapper for it – something that could provide notification and/or graceful failure – and invoke it asynchronously.
    It’s ironic that java provides such facilities as an environment that tries to stay platform independent; using Runtime.exec for something like iexplore.exe on Windows will be most unhappy if the same application is used on a mac. Of course using C# I cheat and invoke processes all the time with System.Diagnostics.Process.Start(“http://foo”) type code but I’m always assuming Windows. I guess it could break on Mono…

  2. >> Instead of using the waitFor() method, I would prefer passing a boolean parameter called waitFor into the exitValue() method to determine whether or not the current thread should wait.

Leave a Reply

Your email address will not be published. Required fields are marked *