java.lang.ProcessBuilder

Lately I have been improving the way I handle the launching of processes on various operating system, namely Windows and UNIX based operating systems. The following is my experience with the handling of proper process launching in Java.

Originally, I was using the java.lang.Runtime class but found that the java.lang.ProcessBuilder class is better. It provides added API that you don’t get with the Runtime class especially when it comes to setting up the executable, current working directory, and most importantly the system environment. Regardless, of what you use, the key is to obtain the system environment so you can manipulate it appropriately. Assuming you already had a ProcessBuilder object called “pb”, the code to obtain the environment is fairly simple:

Map env = pb.environment();

With the environment in hand you can perform many of the natural mapping functions on it. While this is great, you don’t get much control over the map, unfortunately. For example, wouldn’t it be nice to control the order of objects you put in the map or even take out? Nope, not allowed. In fact, when tracing in the debugger, you’ll see random behavior of objects being added to the map. This is unfortunate because let’s say you want the environment to be set up as follows:

APPS_HOME=c:/apps
JAVA_HOME=%APPS_HOME%/java
ANT_HOME=%APPS_HOME%/ant
PATH=%PATH%;%JAVA_HOME%/bin;%ANT_HOME%/bin

Well, you might end up with something like this when the enviroment actually gets used in execution:

JAVA_HOME=%APPS_HOME%/java
ANT_HOME=%APPS_HOME%/ant
APPS_HOME=c:/apps
PATH=%PATH%;%JAVA_HOME%/bin;%ANT_HOME%/bin

Obviously, as shown above, it doesn’t help to have the apps home set AFTER the keys that require it to be set first. The best solution is to ensure that all environment keys being set are purely independent (more on this later). Interestingly, the PATH key always appears last which is very handy as it guarantees that previously defined keys will be picked up properly (if being used in the PATH value).

OK, so that handles the problem of key order and resolution but not entirely. Why? Well, depends on how you want to add new key=value pairs to the environment. In my case, I opted to use XML to define my environment which could then be consumed by my Java code to create the environment I need for launching. The syntax of the XML is simple as I just define an element that accepts key and value attributes. The syntax for value attributes uses the Windows batch script syntax (as shown in the examples above). When it comes to Unix operating systems, a simple algorithm replaces the %% with ${} and semi-colons (;) with colons (:). So, for example, the example shown above written in UNIX syntax is:

APPS_HOME=c:/apps
JAVA_HOME=${APPS_HOME}/java
ANT_HOME=${APPS_HOME}/ant
PATH=${PATH}:${JAVA_HOME}/bin:${ANT_HOME}/bin

Of course, you wouldn’t be using Windows directories on a UNIX system but that is not the point of the example above. Other considerations to take into account prior to launching processes in Java:

  1. Make sure the executable path is quoted when launching on Windows systems to handle directories with spaces or special characters.
  2. When adding key=value pairs where the value references another key, make sure you replace all key references with their actual values. This is important when you are pulling in environments that reference previously defined environments (as mentioned earlier when using XML definitions). The reason is that you can’t expect the system enviornment to do this resolution for you, you must do it beforehand.
  3. Don’t use case checking with environment keys. Let Path = PATH. In other words, if the system enviroment uses “Path” but you define it as “PATH” then let Path=PATH. Otherwise you’ll get multiple entries in your environment and more than likely pick up the wrong values.
Saturday, July 15th, 2006 Software

No comments yet.

Leave a comment

You must be logged in to post a comment.

Search

 

Categories