Calling external commands

(This page was copied from an old version of LabPal; it requires a bit of cleanup.)

So far, we assumed that the execution of an experiment occurs in the execute method of your experiment class. Of course, you can write Java experiment code outside of that method (using any classes and packages you like), and call it from within runExperiment() --this is Java after all. But what if some of your experiment code is not in Java? LabPal provides some helper classes and objects that allow you to run commands at the command line, as well as read and parse their output. Therefore, you can also use external programs in a LabPal experiment suite.

A simple way of doing so is to create an experiment that inherits from the CommandExperiment class. An empty experiment looks as follows:

class ProcedureB extends CommandExperiment {

  public ProcedureB() {
    ...
  }

  public void createCommand(Parameters input, List<String> command) {
  }

  public void readOutput(String output) {
  }
}

The first part of the file is the same boilerplate code as in a regular experiment. In this case, the work happens in the createCommand() and readOutput() methods.

Generating the command to run

The method createCommand() is responsible for creating the command-line string that will be called. Since that external call will probably depend on the experiment's concrete parameters, these parameters are passed as the argument input; you can read from them as usual. The resulting command line is written into the command argument; it is a list of Strings, each of which is a part of the command to run.

Suppose for example that Procedure B takes two numerical parameters, x and y, and requires to call the external program myprogram. Suppose also that the value of x must be passed as is to myprogram, while the value of y must be passed as the -a command-line switch. Method createCommand() could look like this:

public void createCommand(Parameters input, List<String> command) {
    int x = input.getNumber("x").intValue();
    int y = input.getNumber("y").intValue();
    command.add("myprogram").add(x).add("-a " + y);
  }

The first two lines extract the values of x and y as before. The last line creates the command line string. It first adds myprogram, followed by the first argument (the value of x), followed by the second (the value of y passed as the command-line argument -a). If x=2 and y=3, this would result in the following command-line string:

myprogram 2 -a 3

Processing the output

The second part is to do something with the output of the program. To this end, method readOutput() is called once the command has run. It contains in argument output the String of what the command sent to the standard output (if that output contained multiple lines, these lines are present in the string). After processing that string content, you should, as usual, put whatever results of your experiments into the results parameter map.

Suppose that mycommand prints to the standrd output a single number, which we will use as the output z. We need to write the following code:

  public void readOutput(String output, Parameters results) {
    int result = Integer.parseInt(output);
    results.put("z", result);
  }

Of course, it seldom happens that the program's output contains directly the value we are looking for; more often than not, we need to extract that value from a more complicated output. For example, mycommand could output something like this:

The output value of this program is 3. Good bye!

In such a case, you can use Java's standard regular expression matching to parse such a string. Method readOutput() could look like:

  public void readOutput(String output, Parameters results) {
    Pattern p = Pattern.compile("The output value of this program is (\\d+)");
    Matcher m = p.matcher(output);
    if (m.find()) {
      results.put("z", Integer.parseInt(m.group(1)));
    }
  }

This document is by no means a tutorial on regular expressions, but the point is to show how you can use whatever code you wish to break the program's output and make experiment results out of it.

Advantages of extending the CommandExperiment class over running the commands by yourself are multiple:

  • LabPal takes care of starting that command in its own thread, which can be stopped at any time using the GUI

  • LabPal also takes care of watching when the command is finished, gathering its output in a String object and calling readOutput only when all this is over

Last updated