3 * This class can be used to execute a system command from a Java application.
4 * See the documentation for the public methods of this class for more
7 * Documentation for this class is available at this URL:
9 * http://devdaily.com/java/java-processbuilder-process-system-exec
11 * Copyright 2010 alvin j. alexander, devdaily.com.
13 * This program is free software: you can redistribute it and/or modify it under
14 * the terms of the GNU Lesser Public License as published by the Free Software
15 * Foundation, either version 3 of the License, or (at your option) any later
18 * This program is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU Lesser Public License for more details.
22 * You should have received a copy of the GNU Lesser Public License along with
23 * this program. If not, see <http://www.gnu.org/licenses/>.
25 * Please see the following page for the LGPL license:
26 * http://www.gnu.org/licenses/lgpl.txt
30 package org.forester.util;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.util.List;
38 public class SystemCommandExecutor {
40 private final List<String> _command_information;
41 private final String _admin_password;
42 private ThreadedStreamHandler _input_stream_handler;
43 private ThreadedStreamHandler _error_stream_handler;
44 private final static boolean DEBUG = false;
47 * Pass in the system command you want to run as a List of Strings, as shown here:
49 * List<String> commands = new ArrayList<String>();
50 * commands.add("/sbin/ping");
53 * commands.add("www.google.com");
54 * SystemCommandExecutor commandExecutor = new SystemCommandExecutor(commands);
55 * commandExecutor.executeCommand();
57 * Note: I've removed the other constructor that was here to support executing
58 * the sudo command. I'll add that back in when I get the sudo command
59 * working to the point where it won't hang when the given password is
62 * @param command_information The command you want to run.
64 public SystemCommandExecutor( final List<String> command_information ) {
65 if ( ( command_information == null ) || command_information.isEmpty() ) {
66 throw new IllegalArgumentException( "The commandInformation is required." );
68 checkCmdFile( new File( command_information.get( 0 ) ) );
69 _command_information = command_information;
70 _admin_password = null;
73 public static boolean isExecuteableFile( final File path_to_cmd_f ) {
74 if ( !path_to_cmd_f.exists() ) {
77 else if ( path_to_cmd_f.isDirectory() ) {
80 else if ( !path_to_cmd_f.canExecute() ) {
86 private static void checkCmdFile( final File path_to_cmd_f ) {
87 if ( !path_to_cmd_f.exists() ) {
88 throw new IllegalArgumentException( "[" + path_to_cmd_f.getAbsolutePath() + "] does not exist" );
90 else if ( path_to_cmd_f.isDirectory() ) {
91 throw new IllegalArgumentException( "[" + path_to_cmd_f.getAbsolutePath() + "] is a directory" );
93 else if ( !path_to_cmd_f.canExecute() ) {
94 throw new IllegalArgumentException( "[" + path_to_cmd_f.getAbsolutePath() + "] is not executeable" );
98 public int executeCommand() throws IOException, InterruptedException {
101 final ProcessBuilder pb = new ProcessBuilder( _command_information );
103 System.out.println( "command_information=" + _command_information );
105 final Process process = pb.start();
106 // you need this if you're going to write something to the command's input stream
107 // (such as when invoking the 'sudo' command, and it prompts you for a password).
108 final OutputStream stdOutput = process.getOutputStream();
109 // i'm currently doing these on a separate line here in case i need to set them to null
110 // to get the threads to stop.
111 // see http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
112 final InputStream inputStream = process.getInputStream();
113 final InputStream errorStream = process.getErrorStream();
114 // these need to run as java threads to get the standard output and error from the command.
115 // the inputstream handler gets a reference to our stdOutput in case we need to write
116 // something to it, such as with the sudo command
117 _input_stream_handler = new ThreadedStreamHandler( inputStream, stdOutput, _admin_password );
118 _error_stream_handler = new ThreadedStreamHandler( errorStream );
119 // TODO the inputStreamHandler has a nasty side-effect of hanging if the given password is wrong; fix it
120 _input_stream_handler.start();
121 _error_stream_handler.start();
122 // TODO a better way to do this?
123 exit_value = process.waitFor();
124 // TODO a better way to do this?
125 _input_stream_handler.interrupt();
126 _error_stream_handler.interrupt();
127 _input_stream_handler.join();
128 _error_stream_handler.join();
130 catch ( final IOException e ) {
133 catch ( final InterruptedException e ) {
134 // generated by process.waitFor() call
143 * Get the standard error (stderr) from the command you just exec'd.
145 public StringBuilder getStandardErrorFromCommand() {
146 return _error_stream_handler.getOutputBuffer();
150 * Get the standard output (stdout) from the command you just exec'd.
152 public StringBuilder getStandardOutputFromCommand() {
153 return _input_stream_handler.getOutputBuffer();