Christoph Schiessl's Blog

Organizing Java Command-Line Utilities with the Command Pattern

I’m currently working on a command-line utility written in Java to encapsulate a WSDL web service. As you might expect, the web service is exposing a variety of operations with pre-defined parameters to be called. My tool should make these operations accessible to the user, through an easy-to-use command-line interface. Since the web service I’m working with is composed of dozens of operations, I started looking for a design pattern to help me organize my code and discovered the Command Pattern.

The pattern suggests the implementation of a series of command classes with a common public interface to consistently execute their behavior. Command objects may be stored for delayed execution or even to undo the execution of specific commands later on. However, there’s no need for that in a command-line utility and I have therefore omitted this feature from the original pattern. Assuming there’s a one-to-one mapping between WSDL operations and commands, the pattern works pretty well, since it allows a clear separation and the independent implementation of individual operations.

Here’s my abstract super-class for all commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class Command {
  private String[] commandOptions = new String[] {};

  public Command(String[] options) {
    this.commandOptions = options;
  }

  public String[] getCommandOptions() {
    return this.commandOptions;
  }

  public abstract void execute();

  public static String dasherizeName(
    Class<? extends Command> cmd
  ) {
    String n = cmd.getSimpleName().
               replaceAll("Command$", "");
    return n.replaceAll("([a-z])([A-Z])", "$1-$2").
             replaceAll("_", "-").toLowerCase();
  }
}

Apart from defining the public interface for concrete commands (execute()), it is making the passed options (if any) available for sub-classes to use. Last but not least, there’s a static method to “dasherize” the names of command classes: The purpose of this is to convert the class names into a format that is easy to type and to remember for the user.

A concrete command implementation might look like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class GetCustomerCommand extends Command {
  public GetCustomerCommand(String[] options) {
    super(options);
  }

  @Override public void execute() {
    // 1. do something with `options`,
    // 2. call the WSDL operation, and
    // 3. print the operation's result.
    String[] options = getCommandOptions();
    System.out.println("Found customer John Mock!");
  }
}

The UsageCommand is special, because it isn’t encapsulating a WSDL operation. Instead, it is acting as the default command and documenting the application’s other commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UsageCommand extends Command {
  public UsageCommand(String[] options) {
    super(options);
  }

  @Override public void execute() {
    System.out.println("usage:");
    String appName = "fantasy";
    System.out.println(
      appName + " " +
      Command.dasherizeName(GetCustomerCommand.class)
    );
    System.out.println(
      appName + " " +
      Command.dasherizeName(UsageCommand.class)
    );
  }
}

Finally, putting it all together, the main class might look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.Arrays;
public class FantasyServiceWrapper {
  public static void main(String[] args) {
    String name = extractCommandName(args);
    String[] options = extractOptions(args);
    Command command = new UsageCommand(options); // default

    if (compareCommand(GetCustomerCommand.class, name)) {
      command = new GetCustomerCommand(options);
    } else if (compareCommand(CreateCustomerCommand.class, name)) {
      command = new CreateCustomerCommand(options);
    } else if (compareCommand(DeleteCustomerCommand.class, name) {
      command = new DeleteCustomerCommand(options);
    }

    command.execute();
  }

  // the first argument is the dasherized name of the command
  private static String extractCommandName(String[] args) {
    if (args.length == 0) { return null; }
    else { return args[0]; }
  }

  // all other arguments are treated as options and
  //   passed along to the chosen command
  private static String[] extractOptions(String[] args) {
    if (args.length <= 1) { return new String[] {}; }
    else { return Arrays.copyOfRange(args, 1, args.length); }
  }

  private static boolean compareCommand(
    Class<? extends Command> cmd, String name
  ) {
    return Command.dasherizeName(cmd).
           equals(name);
  }
}

Overall, I think this is great way to organize command-line utilities offering many different commands with options. The crucial advantage of the command pattern is that, command implementations can be changed without having to worry about side-effects this might have on other commands; adding new and removing old commands is a straightforward task.

comments powered by Disqus