Saturday, March 17, 2012

Executing External Programs via Java Programs Using Plexus Common Utilities

This tutorial shows how for Java programs to execute external programs using the Plexus Common Utilities library. The Plexus Common Utilities library makes it easier for Java programs to execute external programs and shell commands, and open files such as Word documents, PDF documents, etc with appropriate programs, than with the Runtime interface and ProcessBuilder class in the standard Java API.

This JavaWorld articule, When Runtime.exec() won't by Michael C. Daconta discusses how to use the Runtime interface from the standard Java API in the right way to execute external programs and shell commands. This article, Execute an external program, discusses how to use the Runtime interface and ProcessBuilder class from the standard Java API to execute external programs and open PDF files, etc with appropriate programs. Interested readers can read the two articles to appreciate the convenience brought by the Plexus Common Utilities library in regard to executing external programs and shell commands, and opening files with appropriate programs.

In our first example (Listing 1), we execute a maven command from a Java program. The maven command is mvn clean install. It at first cleans a Maven project, build it, and install the artifact built into the local Maven repository. In the Java program, the maven command is specified via Line 18 and 19. The base directory of the Maven project is specified as the working directory of the execution via Line 20. The center of this example is Line 27, where the executeCommandLine() method is called with three arguments. The first argument, commandline is an object of the type org.codehaus.plexus.util.cli.CommandLine. The commandline object captures the command and working directory to execute the external program, plus arguments to the external program. The second and third arguments, out and err, are two object of the type org.codehaus.plexus.util.cli.CommandLineUtils.StringStreamConsumer. The output and error message of the external program go into out and err respectively. The executeCommandLine() method is overloaded. Readers may look up them via the Plexus Common Utilities API.

Listing 1 - Executing an external program

package plexus.examples;

import java.io.File;

import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;


public class ExternalProgramRunner {
    public static void main(String[] args) {
        String command = "D:\\maven\\bin\\mvn.bat";
        String workingDir = "D:\\examples\\plexus-example";
        String[] arguments = new String[]{"clean", "install"};
        
        Commandline commandline = new Commandline();
        commandline.setExecutable(command);
        commandline.addArguments(arguments);
        commandline.setWorkingDirectory(new File(workingDir));
        
        CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
        CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
        
        int exitCode;
        try {
            exitCode = CommandLineUtils.executeCommandLine(commandline, out, err);
        } catch (CommandLineException e) {
            e.printStackTrace();
        }
        
        String output = out.getOutput();
        if (!StringUtils.isEmpty(output)) {
            System.out.println(output);
        }
        
        String error = err.getOutput();
        if (!StringUtils.isEmpty(error)) {
            System.out.println(error);
        }
    }
}


Output of Listing 1 Execution

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Plexus Example 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ plexus-example ---
[INFO] Deleting D:\examples\plexus-example\target
[INFO]
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ plexus-example ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ plexus-example ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 2 source files to D:\examples\plexus-example\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ plexus-example ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\examples\plexus-example\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ plexus-example ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.7.1:test (default-test) @ plexus-example ---
[INFO] No tests to run.
[INFO] Surefire report directory: D:\examples\plexus-example\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
There are no tests to run.

Results :

Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ plexus-example ---
[INFO] Building jar: D:\examples\plexus-example\target\plexus-example-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ plexus-example ---
[INFO] Installing D:\examples\plexus-example\target\plexus-example-1.0-SNAPSHOT.jar to C:\users\ted\.m2\repository\ted-tutorial\plexus-example\1.0-SNAPSHOT\plexus-example-1.0-SNAPSHOT.jar
[INFO] Installing D:\examples\plexus-example\pom.xml to C:\users\ted\.m2\repository\ted-tutorial\plexus-example\1.0-SNAPSHOT\plexus-example-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.329s
[INFO] Finished at: Sun Mar 18 23:36:37 EDT 2012
[INFO] Final Memory: 8M/245M
[INFO] ------------------------------------------------------------------------


Listing 2 below shows executing a Windows shell command (i.e. dir) from a Java program (the Java program is executed on a Windows machine). The only differences between Listing 2 and 1 lie on Line 13-15.

Listing 2 - Executing a Shell Command

package plexus.examples;

import java.io.File;

import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;


public class ExternalProgramRunner {
    public static void main(String[] args) {
        String command = "dir";
        String workingDir = "D:\\examples\plexus-example";
        
        Commandline commandline = new Commandline();
        commandline.setExecutable(command);
        commandline.setWorkingDirectory(new File(workingDir));
        
        CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
        CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
        
        int exitCode;
        try {
            exitCode = CommandLineUtils.executeCommandLine(commandline, out, err);
        } catch (CommandLineException e) {
            e.printStackTrace();
        }
        
        String output = out.getOutput();
        if (!StringUtils.isEmpty(output)) {
            System.out.println(output);
        }
        
        String error = err.getOutput();
        if (!StringUtils.isEmpty(error)) {
            System.out.println(error);
        }
    }
}

Output of Listing 2 Execution

Directory of D:\\examples\plexus-example

03/18/2012 11:36 PM <DIR> .
03/18/2012 11:36 PM <DIR> ..
03/12/2012 05:34 PM 421 .classpath
03/12/2012 05:34 PM 506 .project
03/12/2012 05:34 PM <DIR> .settings
03/12/2012 05:33 PM 1,330 pom.xml
03/12/2012 05:12 PM <DIR> src
03/18/2012 11:36 PM <DIR> target
3 File(s) 2,257 bytes
5 Dir(s) 554,998,767,616 bytes free

Listing 3 below shows opening a PDF file with an appropriate program (i.e. Adobe Reader) from a Java program. In this example, a PDF file named plexus-guide.pdf is located under D:\docs. Note that nowhere is ever Adobe Reader is mentioned, nevertheless the installation path, in the Java program.Plexus Common Utilities just figures it out behind the scene. The only differences between Listing 3 and 1 lie on Line 13-15.

Listing 3 - Opening a PDF File with Adobe Reader

package plexus.examples;

import java.io.File;

import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;


public class ExternalProgramRunner {
    public static void main(String[] args) {
        String command = "plexus-guide.pdf";
        String workingDir = "D:\\docs";
        
        Commandline commandline = new Commandline();
        commandline.setExecutable(command);
        commandline.setWorkingDirectory(new File(workingDir));
        
        CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
        CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
        
        int exitCode;
        try {
            exitCode = CommandLineUtils.executeCommandLine(commandline, out, err);
        } catch (CommandLineException e) {
            e.printStackTrace();
        }
        
        String output = out.getOutput();
        if (!StringUtils.isEmpty(output)) {
            System.out.println(output);
        }
        
        String error = err.getOutput();
        if (!StringUtils.isEmpty(error)) {
            System.out.println(error);
        }
    }
}

1 comment:

Andy Cohen said...
This comment has been removed by the author.