Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
Panel | ||||||
---|---|---|---|---|---|---|
| ||||||
|
Panel | ||||||
---|---|---|---|---|---|---|
| ||||||
Status | ||||||
---|---|---|---|---|---|---|
|
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 | ||
---|---|---|
| ||
<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 | ||||||
---|---|---|---|---|---|---|
| ||||||
<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 | ||||
---|---|---|---|---|
| ||||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
@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.