Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.


Panel
titleColorwhite
titleBGColor#205081
titleInhalt

Table of Contents



Panel
titleColorwhite
titleBGColor#205081
titleVerweise

API Doc

Bitbucket Repository

Status
colourGreen
titleStatus


Note

This documentation covers the version 2.0.2 of the framework.

The aim of the framework

Splitting complex requirements into little pieces of software is a good approach in software development. Think of micro services: Small pieces of software fulfill a part of functionality. If you put them together you've a powerful application.The smallest unit in the SCF is the Command object. A Command is a java class which provides a little piece of functionality in it's executeCommand() - method. The glue between several Command objects is the ParameterObject. This can be anything derived from java.lang.Object which is not final (of course you want to change values).

Add the framework into your maven project

Code Block
languagexml
<dependency>
    <groupId>org.mwolff</groupId>
    <artifactId>command</artifactId>
    <version>2.0.2</version>
</dependency>

To run unit tests add the following dependency in maven for supporting JUnit 5:

Code Block
languagexml
titlemaven junit dependency
collapsetrue
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>${junit.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>

Browse the JavaDoc for more information

https://mwolff.info/apidocs/simple-command/

Start implementing your first test

Code Block
languagejava
linenumberstrue
package org.mwolff.helloworld;

import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;

import org.junit.Test;
import org.mwolff.command.interfaces.CommandTransition;
import org.mwolff.command.parameterobject.DefaultParameterObject;
import org.mwolff.command.parameterobject.GenericParameterObject;

public class HelloWorldCommandTest {

    /**
     * Tests if getInstance() returns unique instances and the right interface.
     */
    @Test
    public void getInstanceTest() throws Exception {
        HelloWorldCommand hello = HelloWorldCommand.getInstance();
        HelloWorldCommand world = HelloWorldCommand.getInstance();
        assertThat(HelloWorldCommand.getInstance(), instanceOf(HelloWorldCommand.class));
        assertThat(hello, is(not(world)));
    }
    
    /**
     * Tests if the command sets a token named helloworld.message with the right value. 
     */
    @Test
    public void testExecuteHelloWorld() throws Exception {
        GenericParameterObject context = DefaultParameterObject.getInstance();
        CommandTransition result = HelloWorldCommand.getInstance().executeCommand(context);
        assertThat(result, is(CommandTransition.SUCCESS));
        assertThat(context.getAsString("helloworld.message"), is("Hello World"));
    }
}
  • Line 18: The first test is a test of the factory method. It is best practice to provide a factory method for each command.
  • Line 29: Here is the actual implementation of the executeCommand() method. For a simple use of commands this is the entry point of your business logic.
  • Line 30: The framework works with parameter objects. SCF offers a generic implementation of such an object. It is best practice to create your own object but if you want to reuse the command in several environments it make sense just work with the generic one.

We want to assert that a key is generated in the command with value "Hello World" and the command executes with result SUCCESS.

Start implementing your first command


Code Block
languagejava
package org.mwolff.helloworld;

import org.mwolff.command.interfaces.Command;
import org.mwolff.command.CommandException;
import org.mwolff.command.CommandTransitionEnuminterfaces.CommandTransition;
import org.mwolff.command.parameterobject.GenericParameterObject;

public class HelloWorldCommand implements Command<GenericParameterObject> {
    
    public static final HelloWorldCommand getInstance() {
        return new HelloWorldCommand();
    }
    
    @Override
    public CommandTransition executeCommand(GenericParameterObject parameterObject) {
        parameterObject.put("helloworld.message","Hello World");
        return CommandTransition.SUCCESS;
    }
}

To prevent to implement the legacy methods all the time, you can implement an AbstractDefaultCommand.

Create a second command

Code Block
languagejava
package org.mwolff.helloworld;

import static org.hamcrest.CoreMatchers.*;
import static org.junithamcrest.AssertMatcherAssert.*assertThat;
import static org.junit.hamcrestAssert.CoreMatchers*;

import org.junit.Test;
import org.mwolff.command.CommandContainerDefaultCommandContainer;
import org.mwolff.command.CommandTransitionEnuminterfaces.CommandTransitionCommandContainer;
import org.mwolff.command.DefaultCommandContainerinterfaces.CommandTransition;
import org.mwolff.command.parameterobject.DefaultParameterObject;
import org.mwolff.command.parameterobject.GenericParameterObject;

public class SecondCommandTest {

    @Test
    public void getInstanceTest() throws Exception {
        SecondCommand instance = SecondCommand.getInstance();
        assertThat(instance, notNullValue());
        assertThat(instance, CoreMatchers.instanceOf(SecondCommand.class));
    }
    
    @Test
    public void testHowAreYou() throws Exception {
        GenericParameterObject parameterObject = DefaultParameterObject.getInstance();
        parameterObject.put("SecondCommand.helloworld._message","");
        CommandTransition result = SecondCommand.getInstance().executeCommand(parameterObject);
        assertThat(parameterObject.getAsString("SecondCommand.helloworld._message"), is(" How are you?"));
        assertThat(result, is(CommandTransition.SUCCESS));
    }
}


Code Block
languagejava
package org.mwolff.helloworld;

import org.mwolff.command.AbstractDefaultCommand;
import org.mwolff.command.CommandTransitionEnuminterfaces.CommandTransition;
import org.mwolff.command.parameterobject.GenericParameterObject;

//public @since 1.5.1. For older versions you've to implement Command<GenericParameterObject>
public class SecondCommand extends AbstractDefaultCommand<GenericParameterObject>{class SecondCommand extends AbstractDefaultCommand<GenericParameterObject>{

    public static final String helloworld_message = "helloworld.message";
    
    public static final SecondCommand getInstance() {
        return new SecondCommand();
    }

    @Override
    public CommandTransition executeCommand(GenericParameterObject parameterObject) {
        String message = parameterObject.getAsString("helloworld._message");
        message += " How are you?";
        parameterObject.put("helloworld._message", message);
        return CommandTransition.SUCCESS;
    }
}

Sticking both commands together

Code Block
languagejava
    @Test
    public void testBothTogether() throws Exception {
        
        CommandContainer<GenericParameterObject>GenericParameterObject containerparameterObject = new DefaultCommandContainer<>DefaultParameterObject.getInstance();
        GenericParameterObjectCommandContainer<GenericParameterObject> parameterObjectcontainer = DefaultParameterObject.getInstancenew DefaultCommandContainer<>();
        
        CommandTransition result = container
            .addCommand(HelloWorldCommand.getInstance())
            .addCommand(SecondCommand.getInstance())
            .executeCommand(parameterObject);
        
        assertThat(parameterObject.getAsString("SecondCommand.helloworld._message"), is("Hello World How are you?"));
        assertThat(result, is(CommandTransition.SUCCESS));
    }

Conclusion

SCF is a framework is need for all situations where you

  • want to write code fragments, which are loose coupled.
  • want to write command chains which you will execute.
  • want to write strategies.

SCF comes with interfaces and default implementation.

This example is part of simple-command-tools. You can clone it or download it directly here.

Learn more about the Simple Command Framework.