Platinum Partner

Java System Call Platform Independant

One class to copy-paste and run in Java 6, to execute any system command ('dir' or 'ls' or...) in the OS underlying shell. Use and Abstract Factory design-pattern to builds the right shell, or to correctly translates OS-specific commands.

This is a response to the code-challenge of StackOverflow question http://stackoverflow.com/questions/236737/how-to-make-a-system-call-that-returns-the-stdout-output-as-a-string-in-various


package test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

/**
 * Make a system call through a system shell in a platform-independent manner in Java. 
* This class only demonstrate a 'dir' or 'ls' within current (execution) path, if no parameters are used. * If parameters are used, the first one is the system command to execute, the others are its system command parameters.
* To be system independent, an * Abstract Factory Pattern will be used to build the right underlying system shell in which the system command will be executed. * @author VonC * @see How to make a system call that returns the stdout output as a string in various languages? */ public final class JavaSystemCaller { /** * Execute a system command.
* Default is 'ls' in current directory if no parameters, or a system command (if Windows, it is automatically translated to 'dir') * @param args first element is the system command, the others are its parameters (NOT NULL) * @throws IllegalArgumentException if one parameters is null or empty. * 'args' can be empty (default 'ls' performed then) */ public static void main(final String[] args) { String anOutput = ""; if(args.length == 0) { anOutput = Exec.execute("ls"); } else { String[] someParameters = null; anOutput = Exec.execute(args[0],someParameters); } System.out.println("Final output: " + anOutput); } /** * Asynchronously read the output of a given input stream.
* Any exception during execution of the command in managed in this thread. * @author VonC */ public static class StreamGobbler extends Thread { private InputStream is; private String type; private StringBuffer output = new StringBuffer(); StreamGobbler(final InputStream anIs, final String aType) { this.is = anIs; this.type = aType; } /** * Asynchronous read of the input stream.
* Will report output as its its displayed. * @see java.lang.Thread#run() */ @Override public final void run() { try { final InputStreamReader isr = new InputStreamReader(this.is); final BufferedReader br = new BufferedReader(isr); String line=null; while ( (line = br.readLine()) != null) { System.out.println(this.type + ">" + line); this.output.append(line+System.getProperty("line.separator")); } } catch (final IOException ioe) { ioe.printStackTrace(); } } /** * Get output filled asynchronously.
* Should be called after execution * @return final output */ public final String getOutput() { return this.output.toString(); } } /** * Execute a system command in the appropriate shell.
* Read asynchronously stdout and stderr to report any result. * @author VonC */ public static final class Exec { /** * Execute a system command.
* Listen asynchronously to stdout and stderr * @param aCommand system command to be executed (must not be null or empty) * @param someParameters parameters of the command (must not be null or empty) * @return final output (stdout only) */ public static String execute(final String aCommand, final String... someParameters) { String output = ""; try { ExecEnvironmentFactory anExecEnvFactory = getExecEnvironmentFactory(aCommand, someParameters); final IShell aShell = anExecEnvFactory.createShell(); final String aCommandLine = anExecEnvFactory.createCommandLine(); final Runtime rt = Runtime.getRuntime(); System.out.println("Executing " + aShell.getShellCommand() + " " + aCommandLine); final Process proc = rt.exec(aShell.getShellCommand() + " " + aCommandLine); // any error message? final StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR"); // any output? final StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT"); // kick them off errorGobbler.start(); outputGobbler.start(); // any error??? final int exitVal = proc.waitFor(); System.out.println("ExitValue: " + exitVal); output = outputGobbler.getOutput(); } catch (final Throwable t) { t.printStackTrace(); } return output; } private static ExecEnvironmentFactory getExecEnvironmentFactory(final String aCommand, final String... someParameters) { final String anOSName = System.getProperty("os.name" ); if(anOSName.toLowerCase().startsWith("windows")) { return new WindowsExecEnvFactory(aCommand, someParameters); } return new UnixExecEnvFactory(aCommand, someParameters); // TODO be more specific for other OS. } private Exec() { /**/ } } private JavaSystemCaller() { /**/ } /* * ABSTRACT FACTORY PATTERN */ /** * Environment needed to be build for the Exec class to be able to execute the system command.
* Must have the right shell and the right command line.
* @author VonC */ public abstract static class ExecEnvironmentFactory { private String command = null; private ArrayList parameters = new ArrayList(); final String getCommand() { return this.command; } final ArrayList getParameters() { return this.parameters; } /** * Builds an execution environment for a system command to be played.
* Independent from the OS. * @param aCommand system command to be executed (must not be null or empty) * @param someParameters parameters of the command (must not be null or empty) */ public ExecEnvironmentFactory(final String aCommand, final String... someParameters) { if(aCommand == null || aCommand.length() == 0) { throw new IllegalArgumentException("Command must not be empty"); } this.command = aCommand; for (int i = 0; i < someParameters.length; i++) { final String aParameter = someParameters[i]; if(aParameter == null || aParameter.length() == 0) { throw new IllegalArgumentException("Parameter n° '"+i+"' must not be empty"); } this.parameters.add(aParameter); } } /** * Builds the right Shell for the current OS.
* Allow for independent platform execution. * @return right shell, NEVER NULL */ public abstract IShell createShell(); /** * Builds the right command line for the current OS.
* Means that a command might be translated, if it does not fit the right OS ('dir' => 'ls' on unix) * @return right complete command line, with parameters added (NEVER NULL) */ public abstract String createCommandLine(); protected final String buildCommandLine(final String aCommand, final ArrayList someParameters) { final StringBuilder aCommandLine = new StringBuilder(); aCommandLine.append(aCommand); for (String aParameter : someParameters) { aCommandLine.append(" "); aCommandLine.append(aParameter); } return aCommandLine.toString(); } } /** * Builds a Execution Environment for Windows.
* Cmd with windows commands * @author VonC */ public static final class WindowsExecEnvFactory extends ExecEnvironmentFactory { /** * Builds an execution environment for a Windows system command to be played.
* Any command not from windows will be translated in its windows equivalent if possible. * @param aCommand system command to be executed (must not be null or empty) * @param someParameters parameters of the command (must not be null or empty) */ public WindowsExecEnvFactory(final String aCommand, final String... someParameters) { super(aCommand, someParameters); } /** * @see test.JavaSystemCaller.ExecEnvironmentFactory#createShell() */ @Override public IShell createShell() { return new WindowsShell(); } /** * @see test.JavaSystemCaller.ExecEnvironmentFactory#createCommandLine() */ @Override public String createCommandLine() { String aCommand = getCommand(); if(aCommand.toLowerCase().trim().equals("ls")) { aCommand = "dir"; } // TODO translates other Unix commands return buildCommandLine(aCommand, getParameters()); } } /** * Builds a Execution Environment for Unix.
* Sh with Unix commands * @author VonC */ public static final class UnixExecEnvFactory extends ExecEnvironmentFactory { /** * Builds an execution environment for a Unix system command to be played.
* Any command not from Unix will be translated in its Unix equivalent if possible. * @param aCommand system command to be executed (must not be null or empty) * @param someParameters parameters of the command (must not be null or empty) */ public UnixExecEnvFactory(final String aCommand, final String... someParameters) { super(aCommand, someParameters); } /** * @see test.JavaSystemCaller.ExecEnvironmentFactory#createShell() */ @Override public IShell createShell() { return new UnixShell(); } /** * @see test.JavaSystemCaller.ExecEnvironmentFactory#createCommandLine() */ @Override public String createCommandLine() { String aCommand = getCommand(); if(aCommand.toLowerCase().trim().equals("dir")) { aCommand = "ls"; } // TODO translates other Windows commands return buildCommandLine(aCommand, getParameters()); } } /** * System Shell with its right OS command.
* 'cmd' for Windows or 'sh' for Unix, ... * @author VonC */ public interface IShell { /** * Get the right shell command.
* Used to launch a new shell * @return command used to launch a Shell (NEVEL NULL) */ String getShellCommand(); } /** * Windows shell (cmd).
* More accurately 'cmd /C' * @author VonC */ public static class WindowsShell implements IShell { /** * @see test.JavaSystemCaller.IShell#getShellCommand() */ @Override public final String getShellCommand() { final String osName = System.getProperty("os.name" ); if( osName.equals( "Windows 95" ) ) { return "command.com /C"; } return "cmd.exe /C"; } } /** * Unix shell (sh).
* More accurately 'sh -C' * @author VonC */ public static class UnixShell implements IShell { /** * @see test.JavaSystemCaller.IShell#getShellCommand() */ @Override public final String getShellCommand() { return "/bin/sh -c"; } } }
{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}