commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jerome lacoste <>
Subject Re: [exec] API, implementation various notes
Date Fri, 23 Sep 2005 12:31:20 GMT
> I am also voluntary to produce documentation for the package (as said
> to Brett and Trygve yesterday), help redesign things if these small
> redesigns are allowed, making sure if will be used fully in
> CruiseControl and why not help ant migration when it comes.

Some notes below on that regard:

Evaluation of the current commons-exec design.

Process + Runtime.exec (SDK < 5.0)

     String[] cmdarray = new String[] { "myCommand", "myArg1", "myArg2"};
     String[] envp = new String[] {"VAR1=myValue"};
     File workinDir = new File("/tmp");
     Process p = Runtime.exec(cmdarray, envp, workingDir);

- no difference between command and arguments
- when envp == null, current environment inherited fully. Not possible
to remove one variable.
- lack handling of streams (because not consuming them properly can
lead to hangs).
- lack handling of processes
- ugly & confusing Process API (e.g. getInputStream() returns an input
stream that represents the data piped from the output stream. Yuckk)
- nothing makes it really reusable.

ProcessBuilder (SDK >= 5.0)

     ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
     Map<String, String> env = pb.environment();
     env.put("VAR1", "myValue");
     env.put("VAR2", env.get("VAR1") + "suffix");"myDir");
     Process p = pb.start();

     // must handle streams, kill process etc...

Most of the issues fixed.

- streams and Processes still not handled by implementation
- API still ugly (see directory() and command() methods)
- requires SDK 5.0...


current API taken from Ant. Can be reused in several projects (Plexus,
CruiseControl etc...).
Provide beans for easy XML -> Java mapping.

Low level code centered around Execute, CommandLine and Environment.
Similar in one way to what ProcessBuilder tries to do.

     String[] arguments = new String[] {"myArg1", "myArg2"};
     String[] envp = new String[] {"VAR1=myValue"};

     ExecuteStreamHandler streamHandler = new PumpStreamHandler();
     ExecuteWatchdog watchdog = new ExecuteWatchdog();
     Execute execute = new Execute();
     CommandLine commandLine = new CommandLineImpl(cmdarray)
     Environment environment = Environment.getProcEnvironment();
     int result = execute.execute();

Exec: code is broken at best. Tries to hide the complexity of using Execute
Because I find it clumsy I prefered to work directly on top of Execute
when integrating it with CruiseControl.

     Exec exec = new Exec();
     CommandLine commandLine = new CommandLineImpl(cmdarray)
     // exec.setSpawn(true);
     // exec.setNewenvironment(true); // overrides proc env
     // exec.setResolveExecutable(true); //
     exec.setDir(new File());
     // exec.execute(commandLine); // a simpler version (provides
defaults for unspecified parameters/properties. Cover most cases?)
     // but most flexible is
     exec.execute(commandLine, environment, OutputStream,
OutputStream); // hide type of failure

Key benefits
+ Execute.execute() does both process management (kill) and stream management.
  But what complexity needed to use it! Can't use simple things like
String[] and Map. gaaaaa
+ Process is hidden, but could be obtained if we were to add some listeners.
+ Environment.getProcEnvironment(). System.getenv() is SDK 5.0.
+ launchers. But are these used at all? See my TODO_comments.diff patch

- execute make it complex by having both watchdog & process destroyer interfaces
- not enough interfaces (ExecuteWatchdog)
- Lacks the concept of builder for reusability?
- do not have the flexibility ProcessBuilder has with Environment
- Exec: executable resolving (broken)
- Exec: converts failures, timeouts to ExecuteException (sub
IOException) inconditionaly.
- forces inheritance to do something else with the streams (which we
definitively want in CruiseControl). Yuck.


to me commons-exec is slightly over-engineered. As is, clients will
have to resort to strange things and rewrite somewhat complex helper
classes to do simple things.

I propose to change the API.

Vision: Make commons-exec a reusable Library that is available to all
SDK, that not only solves the problems solved by ProcessBuilder but
also add functionality for Process and Stream management, allowing
flexible reuse of this functionality.

For that I need to look at the forces in Action, in particular look at
how this can be improved without requiring too much change in Ant. I
believe it's possible.

Some ideas to make it simpler:
- make Execute less dependent on classes from commons-exec package,
more like a ProcessBuilder for SDK < 5.0.
- is there a need for a package exception. What's wrong with
IOException? Especially as Exec.execute() 'hides' it again (esposes
- is there a need for an Environment class? environment is now a Map
(I've made a patch) so it should be mostly compatible with
For the sake of simplicity I would consider removing the Environment
class (what does it had? type safety?), provide the System.getenv()
compatible functionality currently implemented in
Environment.getProcEnvironment() outside of the Environment class
- ProcessDestroyer / Watchdog. All that can be cleaned up / merged.
- what about merging stdout and stderr as done in ProcessBuilder

See also
For some more notes on design issues.

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message