iamjerryyeung

Saturday, January 14, 2006

Runtime.exec

http://www-128.ibm.com/developerworks/library/j-tiger09304.html?ca=dnt-540
Taming Tiger: Get environment variables and invoke subprocesses
When deprecated doesn't mean forever


Document options
Print this page

E-mail this page

Discuss

Sample code



Rate this page
Help us improve this content




Level: Introductory

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.


30 Sep 2004

Accessing platform-specific information hasn't always been easy. While you could certainly create processes with Runtime.exec(), dealing with differences across platforms to build parameter sets often led to headaches. In addition, the getenv() method of System has been deprecated since the beginning of Java programming time. Now, as columnist John Zukowski shows you, the new ProcessBuilder class makes accessing platform-specific information easier than ever. Share your thoughts on this article with the author and other readers in the accompanying discussion forum. (You can also click Discuss at the top or bottom of the article to access the forum.)
When is a deprecated method not deprecated? When you're using the getenv() method of System. Working in the pre-release versions of the original Java platform back in 1995, Tiger undeprecates the method, along with offering a new class called ProcessBuilder (in the java.lang package) for creating and interacting with system processes.

Getting environment variables

While I personally don't want to go back to the original event model for working with AWT components, one nice feature of the early access version of the Java platform (also known as the alpha releases) was the ability to access environment variables. This approach went against the "Write Once, Run Anywhere" mantra of the time, and the getenv() method of System was deprecated with the 1.0 release of the Java platform. Why something came out deprecated in a 1.0 release always confused me, but seeing the method there always seemed to spark interest in using it with new developers. Fast forward to 2004 and now you finally can. As Listing 1 shows, usage of the method is easy:


Listing 1. Calling getenv

public class EnvTest {
public static void main(String args[]) {
System.out.println(System.getenv(args[0]));
}
}



Simply provide the name on the command line, pass it along to the getenv call, and you'll get its current value. For instance, calling with a PROCESSOR_IDENTIFIER argument produces the results in Listing 2 for my two-year-old desktop system:


Listing 2. getenv sample output

java EnvTest PROCESSOR_IDENTIFIER
x86 Family 6 Model 8 Stepping 6, GenuineIntel



The first thing you should notice is that the method name, getenv(), is all lowercase, not mixed case as you might expect (getEnv()). The reason is because that's the way it was originally named back in pre-release days. Second, accessing environment variables tends to result in platform-specific code. That's all right if it is what you truly want, but it strays from the 100 percent Pure Java model. The code itself is still 100 percent pure, so using the method doesn't totally go against the principle, but after using system properties for so many years, having getenv() around just feels wrong.

Tiger offers two versions of the getenv() method, not just one. The second version returns a name-value pair mapping of all the environment variables currently set in the system. Listing 3 demonstrates the usage of this new method by printing out the key and value of all environment variables:


Listing 3. Getting all environment variables

import java.util.Map;

public class EnvDump {
public static void main(String args[]) {
for (Map.Entry entry: System.getenv().entrySet()) {
System.out.println(entry.getKey() + " / " +
entry.getValue());
}
}
}





Back to top




Understanding ProcessBuilder

This leads us to the new class, java.lang.ProcessBuilder. Earlier versions of the platform allowed you to create native processes through the exec() method of the Runtime class. This approach still works, but with just String arrays as arguments, and a File argument for a working directory, the manner of customizing the sub-process wasn't always that easy. The use of ProcessBuilder simplifies things by adding methods like directory(File) to change the working directory for the process and environment() for adding and removing environment variables from the process space. Listing 4 shows a simple usage of ProcessBuilder to get your Internet configuration with the ipconfig command. This approach should work on most platforms. If it doesn't, change ipconfig to a working command for your platform. After starting the process builder, you need to get its InputStream to read the results of the created process.


Listing 4. Using ProcessBuilder

import java.io.*;

public class ProcessTest {
public static void main(String args[]) throws IOException {
Process p = new ProcessBuilder("ipconfig").start();
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}



As Listing 5 shows, running this program produces output similar to running ipconfig from the command line (your results will most likely vary):


Listing 5. ProcessBuilder example output

Windows 2000 IP Configuration

Ethernet adapter Local Area Connection:

Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . : 192.168.0.101
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.0.1



As I already mentioned, the ProcessBuilder class is a bit more than just forking off a process and getting the results. Prior to calling its start() method, you can adjust the context for the process to execute in. Don't like the environment variables? Just get the current set with environment and clear() out the map. Need to add an environment variable? Call environment to get the current set, then put(name, value) in a new variable. Don't like the working directory? Call directory() with a new working directory as a File object. It really is that simple. Create the ProcessBuilder with a variable number of string arguments representing the command to run and that command's arguments. Once the ProcessBuilder is configured with new environment variables and a working directory, just call start() for the command to run.




Back to top




Ask and ye shall receive...maybe

Are you concerned that your favorite method got deprecated and you want it back? Well, sometimes a deprecated method that was never really supported in a released Java version can come back to life. With enough user demand and votes in Sun's Bug Parade, developers can make a difference and direct how the Java platform evolves. While I doubt the old AWT event model will ever come back to life -- even if everyone demanded it -- something as simple as getting an environment variable is finally supported by the Java platform. Use it with care. Apart from the deprecated getenv issue, ProcessBuilder adds a simpler manner of creating native processes and should be used to replace any old Runtime.exec() calls. Refactor away!





Back to top




Download

Name Size Download method
j-tiger09304-source.zip FTP

Information about download methods

0 Comments:

Post a Comment

<< Home