Tutorial: A good article/untrapment about
Runtime.exec
A good article/untrapment about
Runtime.exec
Tutorial Details:
When Runtime.exec() won't
When Runtime.exec() won't
By: By Michael C. Daconta
Navigate yourself around pitfalls related to the Runtime.exec() method
s part of the Java language, the java.lang package is implicitly imported into every Java program. This package's pitfalls surface often, affecting most programmers. This month, I'll discuss the traps lurking in the Runtime.exec() method.
Pitfall 4: When Runtime.exec() won't
The class java.lang.Runtime features a static method called getRuntime() , which retrieves the current Java Runtime Environment.
That is the only way to obtain a reference to the Runtime object. With that reference, you can run external programs by invoking the Runtime class's exec() method. Developers often call this method to launch a browser for displaying a help page in HTML.
There are four overloaded versions of the exec() command:
public Process exec(String command);
public Process exec(String [] cmdArray);
public Process exec(String command, String [] envp);
public Process exec(String [] cmdArray, String [] envp);
For each of these methods, a command -- and possibly a set of arguments -- is passed to an operating-system-specific function call. This subsequently creates an operating-system-specific process (a running program) with a reference to a Process class returned to the Java VM. The Process class is an abstract class, because a specific subclass of Process exists for each operating system.
You can pass three possible input parameters into these methods:
A single string that represents both the program to execute and any arguments to that program
An array of strings that separate the program from its arguments
An array of environment variables
Pass in the environment variables in the form name=value . If you use the version of exec() with a single string for both the program and its arguments, note that the string is parsed using white space as the delimiter via the StringTokenizer class.
Stumbling into an IllegalThreadStateException
The first pitfall relating to Runtime.exec() is the IllegalThreadStateException . The prevalent first test of an API is to code its most obvious methods. For example, to execute a process that is external to the Java VM, we use the exec() method. To see the value that the external process returns, we use the exitValue() method on the Process class. In our first example, we will attempt to execute the Java compiler ( javac.exe ):
Listing 4.1 BadExecJavac.java
import java.util.*;
import java.io.*;
public class BadExecJavac
{
public static void main(String args[])
{
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
int exitVal = proc.exitValue();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
A run of BadExecJavac produces:
E:\classes\com\javaworld\jpitfalls\article2>java BadExecJavac
java.lang.IllegalThreadStateException: process has not exited
at java.lang.Win32Process.exitValue(Native Method)
at BadExecJavac.main(BadExecJavac.java:13)
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.
Therefore, to avoid this trap, either catch the IllegalThreadStateException or wait for the process to complete.
Now, let's fix the problem in Listing 4.1 and wait for the process to complete. In Listing 4.2, the program again attempts to execute javac.exe and then waits for the external process to complete:
Listing 4.2 BadExecJavac2.java
import java.util.*;
import java.io.*;
public class BadExecJavac2
{
public static void main(String args[])
{
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
Unfortunately, a run of BadExecJavac2 produces no output. The program hangs and never completes. Why does the javac process never complete?
Why Runtime.exec() hangs
The JDK's Javadoc documentation provides the answer to this question:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
Is this just a case of programmers not reading the documentation, as implied in the oft-quoted advice: read the fine manual (RTFM)? The answer is partially yes. In this case, reading the Javadoc would get you halfway there; it explains that you need to handle the streams to your external process, but it does not tell you how.
Another variable is at play here, as is evident by the large number of programmer questions and misconceptions concerning this API in the newsgroups: though Runtime.exec() and the Process APIs seem extremely simple, that simplicity is deceiving because the simple, or obvious, use of the API is prone to error. The lesson here for the API designer is to reserve simple APIs for simple operations. Operations prone to complexities and platform-specific dependencies should reflect the domain accurately. It is possible for an abstraction to be carried too far. The JConfig library provides an example of a more complete API to handle file and process operations (see Resources below for more information).
Now, let's follow the JDK documentation and handle the output of the javac process. When you run javac without any arguments, it produces a set of usage statements that describe how to run the program and the meaning of all the available program options. Knowing that this is going to the stderr stream, you can easily write a program to exhaust that stream before waiting for the process to exit. Listing 4.3 completes that task. While this approach will work, it is not a good general solution. Thus, Listing 4.3's program is named MediocreExecJavac ; it provides only a mediocre solution. A better solution would empty both the standard error stream and the standard output stream. And the best solution would empty these streams simultaneously (I'll demonstrate that later).
Listing 4.3 MediocreExecJavac.java
import java.util.*;
import java.io.*;
public class MediocreExecJavac
{
public static void main(String args[])
{
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
A run of MediocreExecJavac generates:
E:\classes\com\javaworld\jpitfalls\article2>java MediocreExecJavac
Usage: javac where includes:
-g Generate all debugging info
-g:none Generate no debugging info
-g:{lines,vars,source} Generate only some debugging info
-O Optimize; may hinder debugging or enlarge class files
-nowarn Generate no warnings
-verbose Output messages about what the compiler is doing
-deprecation Output source locations where deprecated APIs are used
-classpath Specify where to find user class files
-sourcepath Specify where to find input source files
-bootclasspath Override location of bootstrap class files
-extdirs Override location of installed extensions
-d Specify where to place generated class files
-encoding Specify character encoding used by source files
-target Generate class files for specific VM version
Process exitValue: 2
So, MediocreExecJavac works and produces an exit value of 2 . Normally, an exit value of 0 indicates success; any nonzero value indicates an error. The meaning of these exit values depends on the particular operating system. A Win32 error with a value of 2 is a "file not found" error. That makes sense, since javac expects us to follow the program with the source code file to compile.
Thus, to circumvent the second pitfall -- hanging forever in Runtime.exec() -- if the program you launch produces output or expects input, ensure that you process the input and output streams.
Assuming a command is an executable program
Under the Windows operating system, many new programmers stumble upon Runtime.exec() when trying to use it for nonexecutable commands like dir and copy . Subsequently, they run into Runtime.exec() 's third pitfall. Listing 4.4 demonstrates exactly that:
Listing 4.4 BadExecWinDir.java
import java.util.*;
import java.io.*;
public class BadExecWinDir
{
public static void main(String args[])
{
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("dir
RMI, Dynamic Proxies, and the Evolution of Deployment
RMI, Dynamic Proxies, and the Evolution of Deployment
Dynamic Generation of Stub Classes
This release adds support for the dynamic generation of stub classes at runtime, obviating the need to use the Java Remote Method Invocation (Java RMI) stub compi
SMS-Powered Applications
SMS-Powered Applications
Every business tries to get as close as it can to its customers. The aim is to keep customers up to date with company news, products or service updates, relevant information about their accounts, or to send them notifications for
Creating JSF Custom Components
Creating JSF Custom Components
This article illustrates how to build custom components for use in web applications based on JavaServer Faces (JSF). While JSF comes with a standard set of components, one of the most-publicized features is the easy additio
Groovy, Java\'s New Scripting Language
Groovy, Java\'s New Scripting Language
When some Java developers hear about Groovy, their first reaction often is, as mine was, "Oh, no, not another scripting language for Java." We already have, after all, JavaScript and Rhino, Jython, Jelly, BeanShell,
When tears bring you back your beloved method...
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
JTimepiece
JTimepiece is the advanced library for working with dates and times in Java. Many easy-to-use methods in this API make it easy for any developer, from beginner to expert, to use JTimepiece.
Building Java Server Pages
A detailed look at building JSP pages. Should you use JSP or servlets? It mainly depends on the ratio of markup to code. Here you'll also find a guide to the different varieties of tag, and details about the main tags such as and
Chat Transcript: New Language Features in J2SE 5.0
Java 2 Platform, Standard Edition (J2SE) 5.0. includes the biggest set of language changes since the original release of the Java programming language.
Bioinformatics Tutorials, Links, Programs
Bioinformatics Tutorials, Links, Programs
Bioinformatics Tutorials
Dedicated website to Bioinformatics containing Bioinformatic Tools, Online Resource, Links to Bioinformatic Resources and Tutorials. Here you will find a lot of tutorials and
Building Search Engine Applications Using Servlets !
Building Search Engine Applications Using Servlets !
Building Search Engine Applications Using Servlets
Please visit http://www.webappcabaret.com/javadevelopers/search to see running copy of our search engine.
Introduction
This tutorial takes