At this point we can safely assume that you would like to start some subprocesses from within your Java application and you spent some time here to do it properly. You look at Commons Exec and think "Wow - calling Runtime.exec() is easy and the Apache folks are wasting their and my time with tons of code".
Well, we learned it the hard way (in my case more than once) that using plain Runtime.exec() can be a painful experience. Therefore you are invited to delve into commons-exec and having a look at the hard lessons the easy way ...
Let's look at a real example - we would like to print PDF documents from within your Java application. After googling a while it turns out to be a minor headache and using Adobe Acrobat seems to be a good option.
The command line under Windows should look like "AcroRd32.exe /p /h file" assuming that the Acrobat Reader is found in the path.
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath(); CommandLine commandLine = CommandLine.parse(line); DefaultExecutor executor = new DefaultExecutor(); int exitValue = executor.execute(commandLine);
You successfuly printed your first PDF document but at the end an exception is thrown - what happpend? Mhhmm, Acrobat Reader returned an exit value of '1' on success which is usually considered as an execution failure. So we have to tweak our code to fix this odd behaviour
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath(); CommandLine commandLine = CommandLine.parse(line); DefaultExecutor executor = new DefaultExecutor(); executor.setExitValue(1); int exitValue = executor.execute(commandLine);
You happily printed a while but now your application blocks - your printing subprocess hangs for some obvious or not so obvious reasons. Starting is easy but what to do with a run-away Acrobat Reader?! Luckily commons-exec provides a watchdog doing the work for you and here is the improved code
String line = "AcroRd32.exe /p /h " + file.getAbsolutePath(); CommandLine commandLine = CommandLine.parse(line); ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); DefaultExecutor executor = new DefaultExecutor(); executor.setWatchdog(watchdog); executor.setExitValue(1); int exitValue = executor.execute(commandLine);
Well, the code worked for quite a while until a new customer complained that no documents are printed. It took half a day to find out that the following file 'C:\Document And Settings\documents?432.pdf' could not be printed. Due to the spaces and without further quoting the command line fell literally apart.
> AcroRd32.exe /p /h C:\Document And Settings\documents\432432.pdf
As a quick fix we added double quotes which tells commons-exec to handle the file as a single command line argument instead of splitting it into parts.
String line = "AcroRd32.exe /p /h \"" + file.getAbsolutePath() + "\""; CommandLine commandLine = CommandLine.parse(line); ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); DefaultExecutor executor = new DefaultExecutor(); executor.setWatchdog(watchdog); executor.setExitValue(1); int exitValue = executor.execute(commandLine);
The previous problem stems from the fact that commons-exec tried to split a single command line string into a string array considering single and double quotes. At the end of the day this is error-prone so we recommend building the command line incrementally - according to the same reasoning the Ant documentation does not recommend passing a single command line to the exec target (see deprecated command attribute for exec task)
CommandLine commandLine = CommandLine.parse("AcroRd32.exe");
commandLine.addArguments("/p");
commandLine.addArguments("/h");
commandLine.addArguments(file.getAbsolutePath());
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
DefaultExecutor executor = new DefaultExecutor();
executor.setWatchdog(watchdog);
executor.setExitValue(1);
int exitValue = executor.execute(commandLine);