Skip to content
Bandit Software Factory edited this page Dec 5, 2015 · 9 revisions

Overview

Commandframework is lightweight java library to execute operations (commands) in a fluent and friendly way for the developer. In the commandframework api, there are several key concepts. They are the following:

  • Command : It is the unit of execution.
  • Command repository : It stores all available commands and also it orchestrates the way to access them.

Commandframework has implemented by default some useful commands and some command repositories. On the other hand, commandframework has been designed to be extensible, and for this reason you can use its decorator support (for commands or command repositories) to implement (decorating) your own commands and command repositories.

Let's to see code

Commands

First of all, we are going to see some of the core commands provided by commandframework.

Command sequence

In the first step you has to implement your own command using the Command interface.

public class HelloWorldCommand implements Command {
   public void execute(CommandParams commandParams) throws ExecutionCommandException {
      System.out.println(String.format("Hello world %s", commandParams.getParam("planet", String.class)));
   }
}

After that, check out how you can use the CommandSequence class.

CommandSequence commandSequence = CommandSequenceBuilder.newBuilder()
                                            .addCommand(new HelloWorldCommand())
                                            .addCommand(new HelloWorldCommand())
                                            .addCommand(new HelloWorldCommand())
                                            .build();

commandSequence.execute(HashCommandParamsBuilder.newBuilder().addParam("planet", "Earth").build());

As you can see, the command sequence is composed by three instances of HelloWorldCommand. They are invoked on sequential order. If any error occurs in the first invocation, the other invocations are discarded and the exception is propagated.

Parallel command

This command configuration is very similar than CommandSequence.

ParallelCommand parallelCommand = ParallelCommandBuilder.newBuilder()
                                            .addCommand(new HelloWorldCommand())
                                            .addCommand(new HelloWorldCommand())
                                            .addCommand(new HelloWorldCommand())
                                            .build();
parallelCommand.execute(HashCommandParamsBuilder.newBuilder().addParam("planet", "Earth").build());

Now, the commands are invoked in parallel. The method execute waits until all command are finished.

Recoverable command

RecoverableCommand introduces to you another key concept called ErrorHandler.

  • ErrorHandler : An error handler manages a command exception trying to provide a satisfactory next command invocation.

After this brief explanation, the first step we wanna do is to implement our ErrorHandler.

public class HelloWorldCommandErrorHandler implements ErrorHandler<ExecutionCommandException> {

        public void resolve(ExecutionCommandException commandException, Command command, CommandParams commandParams) throws ExecutionCommandException {
            System.out.println("Before say hello tries to smile");
        }
    }

Again the configuration is very similar to the other commands. Take a look.

RecoverableCommand recoverableCommand = RecoverableCommandBuilder.newBuilder()
                                                .setCommand(new HelloWorldCommand())
                                                .setRetries(3)
                                                .setErrorHandler(ErrorHandlingMappingBuilder.newBuilder()
                                                                .addErrorHandler(new HelloWorldCommandErrorHandler())
                                                                .build()
                                                ).build();

As you can see RecoverableCommand class acts as decorator of your command (in this case HelloWorldCommand), adding the recovery capability. You can configure the maximum number of retries and all required exceptions to handle.

Putting all together

Now is time to see another complex examples using all presented concepts above.

RecoverableCommandBuilder.newBuilder()
                .setCommand(CommandSequenceBuilder.newBuilder()
                        .addCommand(new HelloWorldCommand())
                        .addCommand(new HelloWorldCommand())
                        .addCommand(ParallelCommandBuilder.newBuilder()
                                .addCommand(new HelloWorldCommand())
                                .addCommand(new HelloWorldCommand())
                                .addCommand(RecoverableCommandBuilder.newBuilder()
                                                .setRetries(3)
                                                .setCommand(new HelloWorldCommand())
                                                .setErrorHandler(ErrorHandlingMappingBuilder.newBuilder()
                                                                .addErrorHandler(new HelloWorldCommandErrorHandler())
                                                                .build()
                                                ).build()
                                )
                                .build())
                        .build())
                .setRetries(3)
                .setErrorHandler(ErrorHandlingMappingBuilder.newBuilder()
                                .addErrorHandler(new HelloWorldCommandErrorHandler())
                                .build()
                ).build().execute(HashCommandParamsBuilder.newBuilder().addParam("planet", "Earth").build());

Command repositories

Now it's time to organize our commands. To organize commands you can use command repositories. A command repository provides to you a easy way to access to the commands without need to know implementation details of them and also it permits orchestrates them if necessary. Lest's to see an example.

First of all, we are gonna to configure our command repository.

SimpleCommandRepository<String> myCommandRepository = new SimpleCommandRepository<String>();
myCommandRepository.addCommand("hello world", new HelloWorldCommand());

And finally, as a client of this command repository , we can call "hello world" command as follow:

myCommandRepository.execute("hello world", HashCommandParamsBuilder.newBuilder().addParam("planet", "Earth").build());

That's it.

Decorating command repositories

SimpleCommandRepository<String> commandRepository = new SimpleCommandRepository<String>();
commandRepository.addCommand("hello world", new HelloWorldCommand());
        
BlockingQueueCommandRepository<String> myCommandRepositoryDecorator = new BlockingQueueCommandRepository<String>();
myCommandRepositoryDecorator.setCommandRepository(commandRepository);
myCommandRepositoryDecorator.setTimeout(10000);
myCommandRepositoryDecorator.setBlockingQueue(new ArrayBlockingQueue<CommandRequest>(1));

myCommandRepositoryDecorator.execute("hello world", HashCommandParamsBuilder.newBuilder().addParam("planet", "Earth").build());

Dependencies

Maven

Configure on your settings.xml the following repository:

<repositories>
  <repository>
    <id>bintray</id>
    <url>http://dl.bintray.com/hdbandit/maven</url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
</repositories>

And finally add in your pom.xml the dependency:

<dependency>
  <groupId>com.gvq</groupId>
  <artifactId>commandframework</artifactId>
  <version>1.0.0</version>
</dependency>