SlideShare a Scribd company logo
Apache Commons Chains in Spring Framework 2017
1
Apache Commons Chains in Spring Framework
 Introduction to Apache Commons Chains
Before starting with the Spring integration with Apache Commons Chain , let us start with some basic idea of Apache Commons Chain ,
if you want to cleanly separate the execution and presentation layers without complicating the design of your application then use the
Chain of Responsibility and Command patterns so that the presentation layer can execute a command, or chain of commands, without
needing to know how the command is implemented. In practice, there are usually commands within commands. First, it does some
things for the benefit of the presentation layer, then it executes the business logic, and then it does some more presentation layer
things. The problem many developers face is how to cleanly separate the business logic in the middle of a web command from other
necessary tasks that are part of the request/response transaction.
“A popular technique for organizing the execution of complex processing flows is the "Chain of Responsibility" pattern, as described
(among many other places) in the classic "Gang of Four" design patterns book. Although the fundamental API contracts required to
implement this design pattern are extremely simple, it is useful to have a base API that facilitates using the pattern, and (more
importantly) encouraging composition of command implementations from multiple diverse sources.” -----That is what Apache has to
say ..
The Gang of Four's Chain of Responsibility (COR) behavioural design pattern is interesting and commonly used to model a set of
operations. Each operation needs to be modelled as a command object and linked to others to form a chain. The command objects act
upon some data and indicate whether the control should get passed to the next command in the chain. The benefit is that an operation
can be added or removed easily without changing code. Jakarta Commons Chain models this design pattern as a reusable library. For
successful execution, the arguments and the sub-commands passed from the command line while executing a command should be
made available to the processing code.
The Chain of Responsibility package combines the Command pattern with the classic Chain of Responsibility pattern to make it easy to
call a business command as part of a larger application command.
 Key interfaces of Apache Commons Chains
In the Chain framework, units of work within a sequential flow of steps are represented by commands. A sequence of commands forms a
chain. The chain itself is also a command that can be executed. Chains are kept in catalogs, from which they can be retrieved at the time
of execution. For this purpose, the Chain framework offers the interfaces Chain, Command, and Catalog, see the figure below for a class
diagram.
Fig 1: Class Diagram of the Apache Commons Chains Framework
To implement the patterns, the Chain package defines five key interfaces:
 Context
 Command
 Chain
 Filter
 Catalog
Apache Commons Chains in Spring Framework 2017
2
Context.:A Context represents the state of an application. In the Chain package, Context is a marker interface for a java.util.Map. The
Context is an envelope containing the attributes needed to complete a transaction. In other words, a Context is a stateful object with
member values.
Command.:A Command represents a unit of work. A Command has a single entry method: public boolean execute(Context context). A
Command acts upon the state passed to it through a context object, but retains no state of its own. Commands may be assembled into
a Chain, so that a complex transaction can be created from discrete units of work. If a Command returns true, then other Commands
in a Chain should not be executed. If a Command returns false, then other Commands in the Chain (if any) may execute.
Chain:Chain implements the Command interface, so a Chain can be used interchangeably with a Command. An application doesn't
need to know if it's calling a Chain or a Command, so you can refactor from one to the other. A Chain can nest other Chains as
desired.This property is known as the Liskov substitution principle.( The Liskov Substitution Principle (LSP, lsp) is a concept in
Object Oriented Programming that states: Functions that use pointers or references to base classes must be able to use objects of derived
classes without knowing it.)
Filter.:Ideally, every command would be an island. In real life, we sometimes need to allocate resources and be assured the resources
will be released no matter what happens. A Filter is a specialized Command that adds a postProcess method. A Chain is expected to
call the postProcess method of any filters in the chain before returning. A Command that implements Filter can safely release any
resources it allocated through the postProcess method, even if those resources are shared with other Commands.
Catalog.:Many applications use "facades" and "factories" and other techniques to avoid binding layers too closely together. Layers
need to interact, but often we don't want them to interact at the classname level. A Catalog is a collection of logically named
Commands (or Chains) that a client can execute, without knowing the Command's classname.
Now, we will be discussed each of these key interfaces in details level using a simple coding module , so that you can understand how
a chain of commands works generally.
 Explanation of the key interfaces using a simple code
This example shows how you can use the Commons Chain API to create and execute a sequence of commands. Of course, like almost
every new piece of software written in Java these days, Commons Chain can be configured via an XML file
Step 1 . An implementation of a command
The Chain framework itself contains ready-to-use implementations of Chain and Catalog. This class inherits Command class and
overrides execute method. Here Command is the interface which you must to implement by your class. Each class should have the
execute method where the context object is passed and the return type of the execute method is always Boolean , because it decides
whether a chain will break/to stop the chain further processing or continue executing . The return type true defines that the chain will
break here , where the false defines that the chain will continue executing . All your business logic should be there inside the execute( )
method.
public class Command1 implements Command {
public boolean execute(Context ctx) throws Exception {
System.out.println("This is command1: " );
//Add functionality for Command1
return false;
}
}
Step 2 : A chain-config.xml file
An application using the Chain framework must instantiate a Catalog with chains and commands. This can be done directly by using
the Chain API or by using a configuration file. The latter option offers the most flexibility. Below is the example of a simple
configuration file.
<catalog>
<chain name="a-chain">
<command className="chain.test.Command1"/>
<command className="chain.test.Command2"/>
</chain>
</catalog>
Step 3 : An extension of ContextBase
The Context interface is an extension of the Map interface, but doesn't add any extra methods. The Chain framework
offers ContextBase as a useful implementation of the Context interface. The chain's caller passes YourContext, the property of which is
Apache Commons Chains in Spring Framework 2017
3
set using the setter. The chain's commands do not need to know Context's implementation. They can just retrieve the property
with get("property"). In spite of this flexibility, type-safety is ensured. The command can assign a new value to the property
with ctx.put("property", "a-new-value"), but ctx.put("property", new Object()) yields an UnsupportedOperationException.
The ContextBase uses introspection for the implementation of the get() and put() methods.
public class YourContext extends ContextBase {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String string) {
property = string;
}
}
Step 4 : The execution of a chain
Now the execution of chain of commands can be done using the below code . Here the ConfigParser can be used to instantiate
the Catalog. The Catalog is stored in the singleton CatalogFactoryBase. Because the Catalog doesn't have a name attribute in the
configuration file, it automatically is CatalogFactory's default catalog. Therefore, it can be retrieved by the getCatalog() method. Only
chains or commands that are direct children of Catalog can be retrieved by the getCommand() method. So, the command “Command1 “
cannot be retrieved directly from Catalog. If desired, you can configure “Command1” as a direct child of Catalog. In that
case, Catalog should also have a name attribute.
public class ChainStart {
public static void main(String[] args) {
ChainStart cs = new ChainStart();
//Get the catalog
Catalog catalog = cs.parseConfigFile();
//Get the command
Command command = catalog.getCommand("a-chain");
try {
//Create a context
YourContext ctx = new YourContext();
ctx.setProperty("a-value");
//Execute the command
command.execute(ctx);
} catch (Exception exc) {
System.out.println(exc.toString());
}
}
private Catalog parseConfigFile() {
//Parse the configuration file
ConfigParser parser = new ConfigParser();
String fileLocation = "/chain/test/chain-config.xml";
try {
parser.parse(this.getClass().getResource(fileLocation));
} catch (Exception exc) {
System.out.println(exc.toString());
}
return CatalogFactoryBase.getInstance().getCatalog();
}
}
Mandatory Jars needed to execute the Apache chain-of-commands code
You will need to add this .jars to your classpath, as well. After adding these .jar files to your classpath, the CatalogLoader successfully
compiled and ran. I have mentioned the exact version of the jars that I used. Mismatch of the version may cause the execution error in
the code.
1. The main key packages is the - commons-chain-1.2.jar
2. Commons Digester to read and parse the configuration file - commons-digester-1.8.jar
3. Digester depends on Commons Collections (commons-collections-3.2.1.jar ), Commons Logging (commons-logging-1.2.jar),
and Commons BeanUtils (commoms-beanutils-1.9.3.jar).
Maven dependencies are given below :
1. <dependency>
<groupId>commons-chain</groupId>
<artifactId>commons-chain</artifactId>
Apache Commons Chains in Spring Framework 2017
4
<version>1.2</version>
</dependency>
2. <dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
3. <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
4. <dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>1.8</version>
</dependency>
5. <dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
Example 1 : Basic example of Apache Commons Chain using java program.
Requirement :
1. IDE used : Eclipse
2. Java version used : 1.8
3. Above mentioned Jars.
Steps to create & execute the project :
1. Create a java project Name – ChainProject.
File  New  Java Project Give the project Name  Finish
2. Add all the above mentioned jar in class path.
Right Click on the project Build PathConfigure Build PathSelect Library TabAdd external JarsSelect the above mentioned
jarsApplyOk
3. Create a package under the src , name com.test
Right Click on the src NewPackageFinish
4. Create the below mentioned file and put to com.test folder.
Right click on the package New Give the class Name Finish.
Add the below mentioned class name one by one.
5. Run the main file “ChainStart” to execute and view the output.
Right click on the ChainStart.java Run As Java ApplicationView the output in Console.
1. chain-config.xml
<catalog >
<chain name="a-chain">
<command className="chain.test.Command1"/>
<command className="chain.test.Command2"/>
</chain>
<command name="the-apache-request-parameter-mapper"
className="org.apache.commons.chain.web.servlet.RequestParameterMapper"/>
</catalog>
Apache Commons Chains in Spring Framework 2017
5
2. Command1.java
package chain.test;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class Command1 implements Command {
public boolean execute(Context ctx) throws Exception {
//Add functionality for ACommand1
System.out.println("This is Command 1 ");
String property = (String) ctx.put("property","xyz");
return false; //The chain will resume
}
}
3. Command2.java
package chain.test;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class Command2 implements Command {
public boolean execute(Context ctx) throws Exception {
//Add functionality for ACommand1
System.out.println("This is Command 2 ");
String property = (String) ctx.get("property");
System.out.println("Value from Command 1 in Command2: " + property);
return false; //The chain will resume
}
}
4. YourContext.java
package chain.test;
import org.apache.commons.chain.impl.ContextBase;
public class YourContext extends ContextBase {
private String property;
public String getProperty() {
return property;
}
public void setProperty(String string) {
property = string;
}
}
5. ChainStart.java
package chain.test;
import org.apache.commons.chain.Catalog;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.config.ConfigParser;
import org.apache.commons.chain.impl.CatalogFactoryBase;
public class ChainStart {
private static final String CONFIG_FILE = "/chain/test/chain-config.xml";
private ConfigParser parser;
private Catalog catalog;
public ChainStart() {
parser = new ConfigParser();
}
public Catalog getCatalog() throws Exception {
if (catalog == null) {
Apache Commons Chains in Spring Framework 2017
6
parser.parse(this.getClass().getResource(CONFIG_FILE));
}
catalog = CatalogFactoryBase.getInstance().getCatalog();
return catalog;
}
public static void main(String[] args) throws Exception {
ChainStart chain = new ChainStart();
Catalog catalog = chain.getCatalog();
Command command = catalog.getCommand("a-chain");
Context ctx = new YourContext();
command.execute(ctx);
}
}
Output :
This is Command 1
This is Command 2
Value from Command 1 in Command2: xyz
 Single command Chains & Chains with nested commands
If you want to execute a single command rather than a chain of commands, then you can define the chain-config.xml file as bellow.
 For chain of commands ,pass the chain name in command :
Command command = catalog.getCommand("MyFlow");
 For single command ,pass the command name only in command :
Command command = catalog.getCommand("MyFirstCommand");
<catalog>
<!-- Single command "chains" from CatalogBaseTestCase -->
<command name="MyFirstCommand" className="Command1" />
<command name="MySecondCommand" className="Command2" />
<command name="MySecondCommand" className="Command3" />
<!-- Chains with nested commands -->
<chain name="MyFlow">
<command id="1" className="Command1" />
<command id="2" className="Command2" />
<command id="3" className="Command3" />
</chain>
</catalog>
 Nested Chains & Lookup Commands
Chain supports this concept through the use of nested chains. Since a chain is a command, you can replace a single use of a command
with a reference to another chain. Commons Chain provides the general-use command LookupCommand for discovering and executing
another chain.
Look up a specified Command (which could also be a Chain) in a Catalog, and delegate execution to it. If the delegated-to Command is
also a Filter, its postprocess() method will also be invoked at the appropriate time.
The optional attribute controls how LookupCommand handles the case when the nested chain is not found in the specified catalog.
If optional=true, then the process continues, even if the chain to execute cannot be found. Otherwise, LookupCommand throws
an IllegalArgumentException, indicating that the command could not be found.
Here's the chain configuration with this new flow added to the mix.
<catalog name="main-chain">
<chain name="sell-vehicle">
<command id="command1" className="com.test.nested.sample.Command1" />
<command id="command2" className="com.test.nested.sample.Command2" />
<command id="command3" className="com.test.nested.sample.Command3" />
<command className="org.apache.commons.chain.generic.LookupCommand"
catalogName=" main-chain" name="lookup-chain" optional="true" />
Apache Commons Chains in Spring Framework 2017
7
<command id="command5" className="com.test.nested.sample.Command5" />
</chain>
<chain name="lookup-chain">
<command id="command4" className="com.test.nested.sample.command4" />
</chain>
</catalog>
 Remove Context in Chains
Remove any context attribute using remove(). That context value will not be available in the chain anymore.
public boolean execute(Context context) throws Exception {
context.remove("Context Name","Context Value");
return false;
}
 Filter for exception handling in Chains
A Filter is a specialized Command that also expects the Chain that is executing it to call the postprocess() method if it called
the execute() method. This promise must be fulfilled in spite of any possible exceptions thrown by the execute() method of
this Command, or any subsequent Command whose execute() method was called. The owning Chain must call the postprocess() method
of each Filter in a Chain in reverse order of the invocation of their execute() methods.
The executed command in the example above is a chain, which, in turn, executes the underlying commands as configured. As soon as a
command returns true or whenever an exception occurs, the chain's execution stops. If exception handling within the chain is needed,
the Chain framework offers the interface Filter. From this interface, the postprocess() method is invoked whenever an exception is
thrown in the chain.
public class CommandExceptionHandler implements Filter {
public boolean execute(Context context) throws Exception {
System.out.println("Filter.execute() called.");
return false;
}
public boolean postprocess(Context context, Exception exception) {
if (exception == null) return false;
System.out.println("Exception " + exception.getMessage() + " occurred.");
return true;
}
}
There are three ways of ending a command chain:
1. A command returns true from its execute method.
2. The end of the chain is reached.
3. A command throws an exception.
A command should return true if the chain has completely handled the process. This notion is the basis of the Chain of Responsibility.
Processing is handed off from command to command, until a command handles the command. If no process returns true, before
reaching the end of the command sequence, the chain is assumed to have completed normally.
A chain ends abnormally when any exception is thrown by a command. With Commons Chain, if a command throws an exception, the
chain is broken. The exception, be it a runtime exception or application exception, will bubble up to the original caller of the chain. But
many applications need explicit exception handling that is defined external to any commands. Commons Chain provides a facility for this
using the Filter interface. Filter extends Command, adding a postprocess method.
boolean postprocess(Context context,Exception exception) - execute any cleanup activities, such as releasing resources that were
acquired during the execute() method of this Filter instance.
Commons Chain guarantees that the postprocess method will be called if the Filter's execute method is called, regardless of any thrown
exceptions. Like servlet filters, Chain Filters are executed in the order that they appear in the command sequence. Likewise,
Apache Commons Chains in Spring Framework 2017
8
each Filter's postprocess method is called in reverse order. You can use this feature of Chain to implement exception handlers. Here's
a Filter that traps exceptions that may occur in the sample chain.
The Filter's execute method is called in sequence. However, the postprocess method is not called until the chain reaches its end or a
command throws an exception. If an exception was raised, then the postprocess method handles the exception and returns true,
indicating that the exception was handled. The chain does terminate at this point, but the exception is essentially caught and does not
propagate further. If the postprocess method returns false, the exception bubbles up, causing abnormal termination of the chain.
Example 2 : Example of adding Filter for Exception Handling in Chains using Java Program.
Requirement :
1. IDE used : Eclipse
2. Java version used : 1.8
3. Above mentioned Jars.
Steps to create & execute the project :
1. Create a java project Name – Spring_Chain_Filter.
2. Add all the above mentioned jar in class path.
3. Create a package under the src , name - com.rs.filter.sample
4. Create the below mentioned file and put to com.rs.filter.sample folder.
5. Run the main file “ChainDriver” to execute and view the output.
1. Chain-config.xml
<catalog>
<chain name="main-chain">
<command id="ExceptionHandler"
className ="com.rs.filter.sample.ChainExceptionHandler"/>
<command id="GetCommandInfo" className="com.rs.filter.sample.GetCommandInfo"/>
</chain>
</catalog>
2. GetCommandInfo.java
package com.rs.filter.sample;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class GetCommandInfo implements Command {
public boolean execute(Context ctx) throws Exception {
System.out.println("Get command info");
return false;
}
}
3. ChainExceptionHandler.java
package com.rs.filter.sample;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.Filter;
public class ChainExceptionHandler implements Filter {
public boolean execute(Context context) throws Exception {
System.out.println("Filter.execute() called.");
return false;
}
public boolean postprocess(Context context,Exception exception) {
if (exception == null) return false;
System.out.println("Exception " + exception.getMessage() + " occurred.");
return true;
}
Apache Commons Chains in Spring Framework 2017
9
}
4. ChainDriver.java
package com.rs.filter.sample;
import org.apache.commons.chain.Catalog;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.config.ConfigParser;
import org.apache.commons.chain.impl.CatalogFactoryBase;
import com.jadecove.chain.sample.SellVehicleContext;
public class ChainDriver {
private static final String CONFIG_FILE = "/com/rs/filter/sample/chain-config.xml";
private ConfigParser parser;
private Catalog catalog;
public ChainDriver() {
parser = new ConfigParser();
}
public Catalog getCatalog() throws Exception {
if (catalog == null) {
parser.parse(this.getClass().getResource(CONFIG_FILE));
}
catalog = CatalogFactoryBase.getInstance().getCatalog();
return catalog;
}
public static void main(String[] args) throws Exception {
ChainDriver loader = new ChainDriver();
Catalog sampleCatalog = loader.getCatalog();
Command command = sampleCatalog.getCommand("main-chain");
Context ctx = new SellVehicleContext();
command.execute(ctx);
}
}
Output :
Filter.execute() called.
Get command info
Apache commons chain in Spring framework
So , you are now quite familiar with how the chain of commands actually works .Now , let us come to our main point of discussion that is
the integration of Apache Commons Chains with the Spring framework. Apache APIs do make it simpler to configure, implement and
execute multiple Chains of Responsibilities using spring framework. We will utilize the power that Apache offers and make it Spring
friendly. Here configuring the chain is quite different, as we are using Spring Framework , because instead of relying on Apache way to
configure chains, to make it consistent with all other application beans (classes) we’ll keep chain(s) configuration in Spring.
 Explanation of the key interfaces of Apache commons chain in Spring framework
Step 1: A chain-config.xml file
The chain-config.xml file is somewhat different from the previously discussed chain-config.xml file. Here Spring framework giving us
the reliability to use Apache’s bean org.apache.commons.chain.impl.ChainBase. So, instead of catalog we will use this spring bean
configuration file , that will allows us to configure the chain.
Here the chain “runchain” is configured as “org.apache.commons.chain.impl.ChainBase”, and have two Command classes, that
implement “org.apache.commons.chain.Command” interface, wired in.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
Apache Commons Chains in Spring Framework 2017
10
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<bean name="runchain" class="org.apache.commons.chain.impl.ChainBase">
<constructor-arg>
<util:list>
<ref bean="Command1" />
<ref bean="Command2" />
</util:list>
</constructor-arg>
</bean>
<bean name="Command1" class="com.chain.command.Command1">
<constructor-arg value="Command1...." />
<property name="message1" value =" Command1…"></property>
</bean>
<bean name="Command2" class="com.chain.command.Command2">
<constructor-arg value="Command2....." />
<property name="message2" value =" Command2…."></property>
</bean>
<bean id="chainRunner" class="com.chain.command.ChainRunner" />
</beans>
The best practice is to keep Commands either stateless, or, if they have to have a state – immutable. If this practice is followed, these
Commands can be safely reused throughout many chains (or even as stand-alone utilities). That is the reason, in configuration above,
parameters are injected at Command’s creation time via constructor injection.
Parameters can be injected either by Constructor injection or by Setter injection. Setter injection overrides the constructor injection.
If we use both constructor and setter injection at the same time , IOC container will use the setter injection. So, better to use any one of
them.
Step 2 . An implementation of a command
As already discussed in previous, chain of commands need Command classes for sequential flow of execution. This class inherits
Command class and overrides execute method. In the example given bellow both the constructor and the setter injection are shown ,
but you need to use any one of them.
public class Command1 implements Command {
private String message1;
//using constructor injection
public Command1(String message1) {
super();
this.message1 = message1;
}
//using setter injection
public String getMessage1() {
return message1;
}
public void setMessage1(String message1) {
this.message1 = message1;
}
public boolean execute( Context context ) throws Exception {
System.err.println( message1 );
return false;
}
}
Step 3 : An implementation of interface BeanFactoryAware
If a bean in spring implements BeanFactoryAware then that bean has to implement a method that is setBeanFactory. And when that
bean is loaded in spring container, setBeanFactory is called. BeanFactoryAware belongs to the package
org.springframework.beans.factory. BeanFactoryAware awares the bean for its BeanFactory.
By implementing Spring’s “BeanFactoryAware” interface, at runtime ChainRunner will have a reference to a “beanFactory” which it is
going to use to obtain a reference to the requested chain via “createChain” method.
“ChainRunner” has an entry point which is a “runChain” method, that executes a chain by chain name (bean name in configuration file).
For example, in the configuration shown above “runchain” name can be provided.
It would ideally need to use a couple of custom runtime exceptions: e.g. ChainNotFoundException, IsNotChainException and
ChainExecutionException, but we’ll keep it short here for clarity.
Apache Commons Chains in Spring Framework 2017
11
Alternatively, to strong type chains a bit, “ChainRunner” could take a Map of chains with keys as chain names, and corresponding
“ChainBase” chain objects as values.
“ChainRunner” is pretty much everything that is needed in order to configure an Apache chain in Spring.
public class ChainRunner implements BeanFactoryAware {
private BeanFactory beanFactory;
public void runChain( String chainName ) {
try {
createChain ( chainName ).execute( new ContextBase() );
}
catch ( Exception exc ) {
throw new RuntimeException(
"Chain "" + chainName + "": Execution failed.", exc );
}
}
public void setBeanFactory( BeanFactory beanFactory ) throws BeansException {
this.beanFactory = beanFactory;
}
protected ChainBase createChain( String chainName ) {
return ( ChainBase ) this.beanFactory.getBean( chainName );
}
}
Step 4 : The execution of a chain
Now the execution of chain of commands can be done using the below code . Here we need to create the chainRunner object to pass the
factory and the chain name to execute the chain.
The chain-config.xml can be loaded from anywhere like classpath location or from your local.
 ClassPathXmlApplicationContext: For standalone java applications using XML based configuration.
 FileSystemXmlApplicationContext: Similar to ClassPathXmlApplicationContext except that the xml configuration file can be
loaded from anywhere in the file system.
public class ChainDriver {
public static void main(String[] args) throws Exception {
System.out.println("start......");
ApplicationContext factory = new ClassPathXmlApplicationContext("/com/chain/command/chain-config.xml");
// ApplicationContext factory = new FileSystemXmlApplicationContext("C:UsersniveditamDesktopchain-config.xml");
ChainRunner chainRunner = new ChainRunner();
chainRunner.setBeanFactory(factory);
chainRunner.runChain("runchain");
System.out.println("end.......");
}
}
Step 5 : Passing value in Chain using ContextBase
As discussed in previous ,ContextBase initialize the contents of this Context by copying the values from the specified Map. Any keys
in map that correspond to local properties will cause the setter method for that property to be called.
In addition to the minimal functionality required by the Context interface, this class implements the recommended support
for Attribute-Property Transparency. This is implemented by analysing the available JavaBeans properties of this class (or its subclass),
exposes them as key-value pairs in the Map, with the key being the name of the property itself.
public boolean runChain( String chainName) {
try {
Context context = new ContextBase();
context.put("username", “Nivedita”);
context.put("address1", “Kolkata”);
createChain ( chainName ).execute( context );
}
catch ( Exception ex) {
ex.printStackTrace();
}
}
Apache Commons Chains in Spring Framework 2017
12
Once, this context object is passed in the chain , all values will be available in all the Command classes through context.get() .
Mandatory Jars needed to execute the Apache chain-of-commands code with Spring Framework :
1. All previously mentioned Jars for Apache Common Chains.
2. Spring Jars – You don’t need to add all the Spring Jars to execute this code . Adding these jar will be enough.
i) Spring-beans
ii) Spring-context
iii) Spring-core
iv) Spring expression
3. For testing through JUnit (Optional).
i) Juint
ii) Spring-test
iii) Spring-aop
iv) Hamcrest-all
Example 3 : Basic example of Apache commons chain using Spring framework.
Requirement:
1. IDE used : Eclipse
2. Java version used : 1.8
3. Spring version used : 4.2
4. Above mentioned Jars.
Steps to create & execute the project:
1. Create a java project Name – Spring_Chain.
2. Add all the above mentioned jar in class path.
3. Create a package under the src , name - com.chain.command
4. Create the below mentioned file and put to com.chain.command folder.
5. Run the main file “ChainDriver” to execute and view the output.
1. Chain-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<bean name="runchain" class="org.apache.commons.chain.impl.ChainBase">
<constructor-arg>
<util:list>
<ref bean="Command1" />
<ref bean="Command2" />
</util:list>
</constructor-arg>
</bean>
<bean name="Command1" class="com.chain.command.Command1">
<constructor-arg value="Command1...." />
</bean>
<bean name="Command2" class="com.chain.command.Command2">
<constructor-arg value="Command2....." />
</bean>
<bean id="chainRunner" class="com.chain.command.ChainRunner" />
</beans>
2. Command1.java
package com.chain.command;
import org.apache.commons.chain.Command;
Apache Commons Chains in Spring Framework 2017
13
import org.apache.commons.chain.Context;
public class Command1 implements Command {
private String message1;
public Command1(String message1) {
super();
this.message1 = message1;
}
public boolean execute( Context context ) throws Exception {
System.err.println( message1 );
return false;
}
}
3. Command2.java
package com.chain.command;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class Command2 implements Command {
private String message2;
public Command2(String message2) {
super();
this.message2 = message2;
}
public boolean execute( Context context ) throws Exception {
System.err.println( message2 );
return false;
}
}
4. ChainDriver.java
package com.chain.command;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ChainDriver {
public static void main(String[] args) throws Exception {
System.out.println("Chain start......");
ApplicationContext factory = new ClassPathXmlApplicationContext("/com/chain/command/chain-
config.xml");
ChainRunner chainRunner = new ChainRunner();
chainRunner.setBeanFactory(factory);
chainRunner.runChain("runchain");
System.out.println("Chain end.......");
}
}
5. ChainTest.java (Optional)
package com.chain.command;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class )
@ContextConfiguration( locations={ "/com/chain/command/chain-config.xml"} )
public class ChainTest {
@Resource
ChainRunner chainRunner;
@Test
public void driveTheChain() {
System.out.println("Starting up... [Ok]");
chainRunner.runChain( "runchain" );
System.out.println("Finised... [Ok]");
Apache Commons Chains in Spring Framework 2017
14
}
}
Output :
Chain start......
Command1....
Command2.....
Chain end.......
Apache Commons Chain in Spring MVC Framework
Using the Apache Commons chain in Spring MVC Framework is quite similar to the previously discussed Apache Commons chain in
spring framework. There is no such huge difference in Apache Commons Chain architecture or configuration except the Spring Mvc
Configuration.
Controller :
@Controller is a specific type of component, used in MVC applications and mostly used with RequestMapping annotation.
Many applications use implementations of the Controller pattern to field user requests. A controller as a component that "interacts
with a client, controlling and managing the handling of each request." .Often, an implementation of the Controller pattern will in turn
use the Command pattern or Chain of Command pattern.
In controller we will write a method that will map to a url , by this url the execution will be start up.
@RequestMapping(value = "/ChainOfCommands/runchain", method = RequestMethod.GET, headers = "Accept=application/json")
public void runchain(HttpServletRequest request) {
}
Service :
@Service is used to indicate that a class is a Service. Usually the business facade classes that provide some services are annotated with
this.
In service layer we will define the chainrunner class , that will responsible for executing the command classes.
@Service
public class ChainRunner implements BeanFactoryAware {
}
Commands Class :
Concept of Command classes is same as of previous. All the Command Classes should be kept in a different package for better practice.
Chain-Config.xml:
Concept of Command classes is same as of previous.
So, we need to:
1. Create a Controller.
2. Add a Handler for our Request to the Controller.
3. Create a Request and pass it to the Controller.
4. Create a Chain service that will do all the business implementation.
5. Create Sequential execution of Chain of commands
6. Confirm that the Request returns the expected Response.
Apache Commons Chains in Spring Framework 2017
15
Fig 2: Execution flow of Apache Commons Chain in Spring MVC Framework
Example 4 : Creating a API using Apache Commons Chain in Spring MVC Framework .
Requirement:
1. IDE used : Eclipse
2. Java version used : 1.8
3. Spring version used : 4.2
4. Above mentioned Jars with the additional 2 jar – Spring-web & Spring-webmvc
Steps to create & execute the project:
1. Create a dynamic java project Name – SpringMVC_chain.
2. Add all spring jar and the above mentioned jar in class path.
3. Add the Spring-servlet.xml & web.xml under WEB-INF
4. Create a package under the src , name - com.chain.Controller, put the ChainController class there.
5. Create a package under the src , name - com.chain.Service. put the ChainRunnerService class there.
6. Create a package under the src , name com.chain.Command folder. Add all the Command classes.
7. Keep the chain-config.xml file under the src.
8. Start the server.
9. Hit the API url using browser/rest client.
The project structure should look like the below structure –
1. CommandA.java
Apache Commons Chains in Spring Framework 2017
16
package com.chain.Commands;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class CommandA implements Command {
private String message;
public CommandA( String message ) {
this.message = message;
}
public boolean execute( Context context ) throws Exception {
System.out.println("CommandA....."+message);
return false;
}
}
2. CommandB.java
package com.chain.Commands;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class CommandB implements Command {
private String message;
public CommandB( String message ) {
this.message = message;
}
public boolean execute( Context context ) throws Exception {
System.err.println("CommandB....."+message);
return false;
}
}
3. CommandC.java
package com.chain.Commands;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
public class CommandC implements Command {
private String message;
public CommandC( String message ) {
this.message = message;
}
public boolean execute( Context context ) throws Exception {
System.out.println("CommandC......"+message);
return false;
}
}
4. ChainController.java
package com.chain.Controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.chain.Service.ChainRunnerService;
Apache Commons Chains in Spring Framework 2017
17
@RestController
public class ChainController {
@Autowired
ChainRunnerService chainRunnerService;
@RequestMapping(value = "/ChainOfCommands/runchain", method = RequestMethod.GET, headers =
"Accept=application/json")
public void runchain(HttpServletRequest request) {
System.out.println("start......");
ApplicationContext factory = new ClassPathXmlApplicationContext("chain-config.xml");
chainRunnerService.setBeanFactory(factory);
chainRunnerService.runChain("mvcchain");
System.out.println("end.......");
}
}
5. ChainRunnerService.java
package com.chain.Service;
import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.impl.ContextBase;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Service;
@Service
public class ChainRunnerService implements BeanFactoryAware {
private BeanFactory beanFactory;
public void runChain( String chainName ) {
try {
createChain ( chainName ).execute( new ContextBase() );
}
catch ( Exception exc ) {
throw new RuntimeException(
"Chain "" + chainName + "": Execution failed.", exc );
}
}
public void setBeanFactory( BeanFactory beanFactory ) throws BeansException {
this.beanFactory = beanFactory;
}
protected ChainBase createChain( String chainName ) {
return ( ChainBase ) this.beanFactory.getBean( chainName );
}
}
6. Chain-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<bean name="mvcchain" class="org.apache.commons.chain.impl.ChainBase">
<constructor-arg>
<list>
<ref bean="commandA" />
<ref bean="commandB" />
<ref bean="commandC" />
</list>
</constructor-arg>
</bean>
Apache Commons Chains in Spring Framework 2017
18
<bean name="commandA" class="com.chain.Commands.CommandA">
<constructor-arg value="commandA" />
</bean>
<bean name="commandB" class="com.chain.Commands.CommandB">
<constructor-arg value="commandB" />
</bean>
<bean name="commandC" class="com.chain.Commands.CommandC">
<constructor-arg value="commandC" />
</bean>
<bean id="chainRunner" class="com.chain.Service.ChainRunnerService" />
</beans>
Run & Execution :
Make a HTTP GET Request with http://localhost:8080/SpringMVCchain/ChainOfCommands/runchain
Console Output :
start......
CommandA.....commandA
CommandB.....commandB
CommandC......commandC
end.......
Limitation
Chain is not a full workflow system. It does not have sophisticated flow of control between branches of chains or looping. However, it is
also easier to get started with than most workflow systems and you can easily refactor existing code to fit within it. Editing the XML file
to change the sequence of commands or alter the parameters passed to a command is also well within the realm of what many end
users can do themselves without minimal instruction.
******KEY NOTES******
 This framework, developed under the community umbrella of the Jakarta Commons project
 Key package - org.apache.commons.chain
 Classes - Command, ContextBase, Filter
 Main classes – ContextBase
 Exception handling and post process – Filter
 Utility classes for loading - Catalog, config.ConfigParser, impl.CatalogFactoryBase
 Used as a glue to bind commands - ContextBase
 Implementations of Context must also implement all of the required and optional contracts of the java.util.Map interface.
Reference
http://commons.apache.org/proper/commons-chain/
https://commons.apache.org/proper/commons-chain/apidocs/

More Related Content

PDF
인생은 짧아요, 엑셀 대신 파이썬
PPT
Error Handling in Mulesoft
PDF
Cassandra Consistency: Tradeoffs and Limitations
PDF
Elasticsearch
PDF
Future of Integration | MuleSoft
ODP
Introduction to Kafka connect
PDF
How Apache Kafka® Works
PPTX
Managing APIs with MuleSoft
인생은 짧아요, 엑셀 대신 파이썬
Error Handling in Mulesoft
Cassandra Consistency: Tradeoffs and Limitations
Elasticsearch
Future of Integration | MuleSoft
Introduction to Kafka connect
How Apache Kafka® Works
Managing APIs with MuleSoft

What's hot (20)

PDF
Empowering Your Java Applications with Quarkus. A New Era of Fast, Efficient,...
PDF
ChatGPT and not only: how can you use the power of Generative AI at scale
PPTX
AWS Elastic Beanstalk
PPTX
Mulesoft Anypoint platform: Design Center
PDF
Auto scaling using Amazon Web Services ( AWS )
PPTX
Product Vision and Roadmap for Anypoint Platform
PPTX
Mulesoft Connections to different companies, and different services
PPTX
MuleSoft Architecture Presentation
PDF
Using the power of OpenAI with your own data: what's possible and how to start?
PDF
AI and ML Series - Introduction to Generative AI and LLMs - Session 1
PPTX
Benefits of integration with the Mulesoft Anypoint Platform
PDF
Machine Learning using Kubeflow and Kubernetes
PPTX
Designing Apps for Runtime Fabric: Logging, Monitoring & Object Store Persist...
PDF
Inside HDFS Append
PPTX
Data Streaming with Apache Kafka & MongoDB
PDF
Expose your event-driven data to the outside world using webhooks powered by ...
PPTX
WebSphere App Server vs JBoss vs WebLogic vs Tomcat (InterConnect 2016)
PPTX
Data Pipelines with Kafka Connect
PPTX
AI Tools for Productivity: Exploring Prompt Engineering and Key Features
PDF
Microservice architecture
Empowering Your Java Applications with Quarkus. A New Era of Fast, Efficient,...
ChatGPT and not only: how can you use the power of Generative AI at scale
AWS Elastic Beanstalk
Mulesoft Anypoint platform: Design Center
Auto scaling using Amazon Web Services ( AWS )
Product Vision and Roadmap for Anypoint Platform
Mulesoft Connections to different companies, and different services
MuleSoft Architecture Presentation
Using the power of OpenAI with your own data: what's possible and how to start?
AI and ML Series - Introduction to Generative AI and LLMs - Session 1
Benefits of integration with the Mulesoft Anypoint Platform
Machine Learning using Kubeflow and Kubernetes
Designing Apps for Runtime Fabric: Logging, Monitoring & Object Store Persist...
Inside HDFS Append
Data Streaming with Apache Kafka & MongoDB
Expose your event-driven data to the outside world using webhooks powered by ...
WebSphere App Server vs JBoss vs WebLogic vs Tomcat (InterConnect 2016)
Data Pipelines with Kafka Connect
AI Tools for Productivity: Exploring Prompt Engineering and Key Features
Microservice architecture
Ad

Similar to Apache commons chain in Spring Framework (20)

PDF
Java concurrency
ODP
Mule ctf
PPTX
ADO.NET by ASP.NET Development Company in india
PDF
Concurrency and parallel in .net
PDF
Why Laravel?
DOCX
systemverilog-interview-questions.docx
PDF
Building Automated Data Pipelines with Airflow.pdf
PDF
Query service in vCloud Director
DOCX
MCS,BCS-7(A,B) Visual programming Syllabus for Final exams @ ISP
PPTX
Azure Durable Functions
PDF
Spring 2
PPTX
Java J2EE Interview Questions Part 2
PPTX
Java J2EE Interview Question Part 2
PDF
What is new in java 8 concurrency
PDF
You are to simulate a dispatcher using a priority queue system.New.pdf
PDF
Jinal desai .net
ODT
Designing Better API
PPTX
Multithreading and concurrency in android
PDF
Scala tutorial
PDF
Scala tutorial
Java concurrency
Mule ctf
ADO.NET by ASP.NET Development Company in india
Concurrency and parallel in .net
Why Laravel?
systemverilog-interview-questions.docx
Building Automated Data Pipelines with Airflow.pdf
Query service in vCloud Director
MCS,BCS-7(A,B) Visual programming Syllabus for Final exams @ ISP
Azure Durable Functions
Spring 2
Java J2EE Interview Questions Part 2
Java J2EE Interview Question Part 2
What is new in java 8 concurrency
You are to simulate a dispatcher using a priority queue system.New.pdf
Jinal desai .net
Designing Better API
Multithreading and concurrency in android
Scala tutorial
Scala tutorial
Ad

Recently uploaded (20)

PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Machine learning based COVID-19 study performance prediction
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Network Security Unit 5.pdf for BCA BBA.
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Digital-Transformation-Roadmap-for-Companies.pptx
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Empathic Computing: Creating Shared Understanding
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Chapter 3 Spatial Domain Image Processing.pdf
Encapsulation_ Review paper, used for researhc scholars
Per capita expenditure prediction using model stacking based on satellite ima...
Building Integrated photovoltaic BIPV_UPV.pdf
20250228 LYD VKU AI Blended-Learning.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
Diabetes mellitus diagnosis method based random forest with bat algorithm
Machine learning based COVID-19 study performance prediction
MYSQL Presentation for SQL database connectivity
Network Security Unit 5.pdf for BCA BBA.

Apache commons chain in Spring Framework

  • 1. Apache Commons Chains in Spring Framework 2017 1 Apache Commons Chains in Spring Framework  Introduction to Apache Commons Chains Before starting with the Spring integration with Apache Commons Chain , let us start with some basic idea of Apache Commons Chain , if you want to cleanly separate the execution and presentation layers without complicating the design of your application then use the Chain of Responsibility and Command patterns so that the presentation layer can execute a command, or chain of commands, without needing to know how the command is implemented. In practice, there are usually commands within commands. First, it does some things for the benefit of the presentation layer, then it executes the business logic, and then it does some more presentation layer things. The problem many developers face is how to cleanly separate the business logic in the middle of a web command from other necessary tasks that are part of the request/response transaction. “A popular technique for organizing the execution of complex processing flows is the "Chain of Responsibility" pattern, as described (among many other places) in the classic "Gang of Four" design patterns book. Although the fundamental API contracts required to implement this design pattern are extremely simple, it is useful to have a base API that facilitates using the pattern, and (more importantly) encouraging composition of command implementations from multiple diverse sources.” -----That is what Apache has to say .. The Gang of Four's Chain of Responsibility (COR) behavioural design pattern is interesting and commonly used to model a set of operations. Each operation needs to be modelled as a command object and linked to others to form a chain. The command objects act upon some data and indicate whether the control should get passed to the next command in the chain. The benefit is that an operation can be added or removed easily without changing code. Jakarta Commons Chain models this design pattern as a reusable library. For successful execution, the arguments and the sub-commands passed from the command line while executing a command should be made available to the processing code. The Chain of Responsibility package combines the Command pattern with the classic Chain of Responsibility pattern to make it easy to call a business command as part of a larger application command.  Key interfaces of Apache Commons Chains In the Chain framework, units of work within a sequential flow of steps are represented by commands. A sequence of commands forms a chain. The chain itself is also a command that can be executed. Chains are kept in catalogs, from which they can be retrieved at the time of execution. For this purpose, the Chain framework offers the interfaces Chain, Command, and Catalog, see the figure below for a class diagram. Fig 1: Class Diagram of the Apache Commons Chains Framework To implement the patterns, the Chain package defines five key interfaces:  Context  Command  Chain  Filter  Catalog
  • 2. Apache Commons Chains in Spring Framework 2017 2 Context.:A Context represents the state of an application. In the Chain package, Context is a marker interface for a java.util.Map. The Context is an envelope containing the attributes needed to complete a transaction. In other words, a Context is a stateful object with member values. Command.:A Command represents a unit of work. A Command has a single entry method: public boolean execute(Context context). A Command acts upon the state passed to it through a context object, but retains no state of its own. Commands may be assembled into a Chain, so that a complex transaction can be created from discrete units of work. If a Command returns true, then other Commands in a Chain should not be executed. If a Command returns false, then other Commands in the Chain (if any) may execute. Chain:Chain implements the Command interface, so a Chain can be used interchangeably with a Command. An application doesn't need to know if it's calling a Chain or a Command, so you can refactor from one to the other. A Chain can nest other Chains as desired.This property is known as the Liskov substitution principle.( The Liskov Substitution Principle (LSP, lsp) is a concept in Object Oriented Programming that states: Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.) Filter.:Ideally, every command would be an island. In real life, we sometimes need to allocate resources and be assured the resources will be released no matter what happens. A Filter is a specialized Command that adds a postProcess method. A Chain is expected to call the postProcess method of any filters in the chain before returning. A Command that implements Filter can safely release any resources it allocated through the postProcess method, even if those resources are shared with other Commands. Catalog.:Many applications use "facades" and "factories" and other techniques to avoid binding layers too closely together. Layers need to interact, but often we don't want them to interact at the classname level. A Catalog is a collection of logically named Commands (or Chains) that a client can execute, without knowing the Command's classname. Now, we will be discussed each of these key interfaces in details level using a simple coding module , so that you can understand how a chain of commands works generally.  Explanation of the key interfaces using a simple code This example shows how you can use the Commons Chain API to create and execute a sequence of commands. Of course, like almost every new piece of software written in Java these days, Commons Chain can be configured via an XML file Step 1 . An implementation of a command The Chain framework itself contains ready-to-use implementations of Chain and Catalog. This class inherits Command class and overrides execute method. Here Command is the interface which you must to implement by your class. Each class should have the execute method where the context object is passed and the return type of the execute method is always Boolean , because it decides whether a chain will break/to stop the chain further processing or continue executing . The return type true defines that the chain will break here , where the false defines that the chain will continue executing . All your business logic should be there inside the execute( ) method. public class Command1 implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("This is command1: " ); //Add functionality for Command1 return false; } } Step 2 : A chain-config.xml file An application using the Chain framework must instantiate a Catalog with chains and commands. This can be done directly by using the Chain API or by using a configuration file. The latter option offers the most flexibility. Below is the example of a simple configuration file. <catalog> <chain name="a-chain"> <command className="chain.test.Command1"/> <command className="chain.test.Command2"/> </chain> </catalog> Step 3 : An extension of ContextBase The Context interface is an extension of the Map interface, but doesn't add any extra methods. The Chain framework offers ContextBase as a useful implementation of the Context interface. The chain's caller passes YourContext, the property of which is
  • 3. Apache Commons Chains in Spring Framework 2017 3 set using the setter. The chain's commands do not need to know Context's implementation. They can just retrieve the property with get("property"). In spite of this flexibility, type-safety is ensured. The command can assign a new value to the property with ctx.put("property", "a-new-value"), but ctx.put("property", new Object()) yields an UnsupportedOperationException. The ContextBase uses introspection for the implementation of the get() and put() methods. public class YourContext extends ContextBase { private String property; public String getProperty() { return property; } public void setProperty(String string) { property = string; } } Step 4 : The execution of a chain Now the execution of chain of commands can be done using the below code . Here the ConfigParser can be used to instantiate the Catalog. The Catalog is stored in the singleton CatalogFactoryBase. Because the Catalog doesn't have a name attribute in the configuration file, it automatically is CatalogFactory's default catalog. Therefore, it can be retrieved by the getCatalog() method. Only chains or commands that are direct children of Catalog can be retrieved by the getCommand() method. So, the command “Command1 “ cannot be retrieved directly from Catalog. If desired, you can configure “Command1” as a direct child of Catalog. In that case, Catalog should also have a name attribute. public class ChainStart { public static void main(String[] args) { ChainStart cs = new ChainStart(); //Get the catalog Catalog catalog = cs.parseConfigFile(); //Get the command Command command = catalog.getCommand("a-chain"); try { //Create a context YourContext ctx = new YourContext(); ctx.setProperty("a-value"); //Execute the command command.execute(ctx); } catch (Exception exc) { System.out.println(exc.toString()); } } private Catalog parseConfigFile() { //Parse the configuration file ConfigParser parser = new ConfigParser(); String fileLocation = "/chain/test/chain-config.xml"; try { parser.parse(this.getClass().getResource(fileLocation)); } catch (Exception exc) { System.out.println(exc.toString()); } return CatalogFactoryBase.getInstance().getCatalog(); } } Mandatory Jars needed to execute the Apache chain-of-commands code You will need to add this .jars to your classpath, as well. After adding these .jar files to your classpath, the CatalogLoader successfully compiled and ran. I have mentioned the exact version of the jars that I used. Mismatch of the version may cause the execution error in the code. 1. The main key packages is the - commons-chain-1.2.jar 2. Commons Digester to read and parse the configuration file - commons-digester-1.8.jar 3. Digester depends on Commons Collections (commons-collections-3.2.1.jar ), Commons Logging (commons-logging-1.2.jar), and Commons BeanUtils (commoms-beanutils-1.9.3.jar). Maven dependencies are given below : 1. <dependency> <groupId>commons-chain</groupId> <artifactId>commons-chain</artifactId>
  • 4. Apache Commons Chains in Spring Framework 2017 4 <version>1.2</version> </dependency> 2. <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency> 3. <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> 4. <dependency> <groupId>commons-digester</groupId> <artifactId>commons-digester</artifactId> <version>1.8</version> </dependency> 5. <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> Example 1 : Basic example of Apache Commons Chain using java program. Requirement : 1. IDE used : Eclipse 2. Java version used : 1.8 3. Above mentioned Jars. Steps to create & execute the project : 1. Create a java project Name – ChainProject. File  New  Java Project Give the project Name  Finish 2. Add all the above mentioned jar in class path. Right Click on the project Build PathConfigure Build PathSelect Library TabAdd external JarsSelect the above mentioned jarsApplyOk 3. Create a package under the src , name com.test Right Click on the src NewPackageFinish 4. Create the below mentioned file and put to com.test folder. Right click on the package New Give the class Name Finish. Add the below mentioned class name one by one. 5. Run the main file “ChainStart” to execute and view the output. Right click on the ChainStart.java Run As Java ApplicationView the output in Console. 1. chain-config.xml <catalog > <chain name="a-chain"> <command className="chain.test.Command1"/> <command className="chain.test.Command2"/> </chain> <command name="the-apache-request-parameter-mapper" className="org.apache.commons.chain.web.servlet.RequestParameterMapper"/> </catalog>
  • 5. Apache Commons Chains in Spring Framework 2017 5 2. Command1.java package chain.test; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class Command1 implements Command { public boolean execute(Context ctx) throws Exception { //Add functionality for ACommand1 System.out.println("This is Command 1 "); String property = (String) ctx.put("property","xyz"); return false; //The chain will resume } } 3. Command2.java package chain.test; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class Command2 implements Command { public boolean execute(Context ctx) throws Exception { //Add functionality for ACommand1 System.out.println("This is Command 2 "); String property = (String) ctx.get("property"); System.out.println("Value from Command 1 in Command2: " + property); return false; //The chain will resume } } 4. YourContext.java package chain.test; import org.apache.commons.chain.impl.ContextBase; public class YourContext extends ContextBase { private String property; public String getProperty() { return property; } public void setProperty(String string) { property = string; } } 5. ChainStart.java package chain.test; import org.apache.commons.chain.Catalog; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.apache.commons.chain.config.ConfigParser; import org.apache.commons.chain.impl.CatalogFactoryBase; public class ChainStart { private static final String CONFIG_FILE = "/chain/test/chain-config.xml"; private ConfigParser parser; private Catalog catalog; public ChainStart() { parser = new ConfigParser(); } public Catalog getCatalog() throws Exception { if (catalog == null) {
  • 6. Apache Commons Chains in Spring Framework 2017 6 parser.parse(this.getClass().getResource(CONFIG_FILE)); } catalog = CatalogFactoryBase.getInstance().getCatalog(); return catalog; } public static void main(String[] args) throws Exception { ChainStart chain = new ChainStart(); Catalog catalog = chain.getCatalog(); Command command = catalog.getCommand("a-chain"); Context ctx = new YourContext(); command.execute(ctx); } } Output : This is Command 1 This is Command 2 Value from Command 1 in Command2: xyz  Single command Chains & Chains with nested commands If you want to execute a single command rather than a chain of commands, then you can define the chain-config.xml file as bellow.  For chain of commands ,pass the chain name in command : Command command = catalog.getCommand("MyFlow");  For single command ,pass the command name only in command : Command command = catalog.getCommand("MyFirstCommand"); <catalog> <!-- Single command "chains" from CatalogBaseTestCase --> <command name="MyFirstCommand" className="Command1" /> <command name="MySecondCommand" className="Command2" /> <command name="MySecondCommand" className="Command3" /> <!-- Chains with nested commands --> <chain name="MyFlow"> <command id="1" className="Command1" /> <command id="2" className="Command2" /> <command id="3" className="Command3" /> </chain> </catalog>  Nested Chains & Lookup Commands Chain supports this concept through the use of nested chains. Since a chain is a command, you can replace a single use of a command with a reference to another chain. Commons Chain provides the general-use command LookupCommand for discovering and executing another chain. Look up a specified Command (which could also be a Chain) in a Catalog, and delegate execution to it. If the delegated-to Command is also a Filter, its postprocess() method will also be invoked at the appropriate time. The optional attribute controls how LookupCommand handles the case when the nested chain is not found in the specified catalog. If optional=true, then the process continues, even if the chain to execute cannot be found. Otherwise, LookupCommand throws an IllegalArgumentException, indicating that the command could not be found. Here's the chain configuration with this new flow added to the mix. <catalog name="main-chain"> <chain name="sell-vehicle"> <command id="command1" className="com.test.nested.sample.Command1" /> <command id="command2" className="com.test.nested.sample.Command2" /> <command id="command3" className="com.test.nested.sample.Command3" /> <command className="org.apache.commons.chain.generic.LookupCommand" catalogName=" main-chain" name="lookup-chain" optional="true" />
  • 7. Apache Commons Chains in Spring Framework 2017 7 <command id="command5" className="com.test.nested.sample.Command5" /> </chain> <chain name="lookup-chain"> <command id="command4" className="com.test.nested.sample.command4" /> </chain> </catalog>  Remove Context in Chains Remove any context attribute using remove(). That context value will not be available in the chain anymore. public boolean execute(Context context) throws Exception { context.remove("Context Name","Context Value"); return false; }  Filter for exception handling in Chains A Filter is a specialized Command that also expects the Chain that is executing it to call the postprocess() method if it called the execute() method. This promise must be fulfilled in spite of any possible exceptions thrown by the execute() method of this Command, or any subsequent Command whose execute() method was called. The owning Chain must call the postprocess() method of each Filter in a Chain in reverse order of the invocation of their execute() methods. The executed command in the example above is a chain, which, in turn, executes the underlying commands as configured. As soon as a command returns true or whenever an exception occurs, the chain's execution stops. If exception handling within the chain is needed, the Chain framework offers the interface Filter. From this interface, the postprocess() method is invoked whenever an exception is thrown in the chain. public class CommandExceptionHandler implements Filter { public boolean execute(Context context) throws Exception { System.out.println("Filter.execute() called."); return false; } public boolean postprocess(Context context, Exception exception) { if (exception == null) return false; System.out.println("Exception " + exception.getMessage() + " occurred."); return true; } } There are three ways of ending a command chain: 1. A command returns true from its execute method. 2. The end of the chain is reached. 3. A command throws an exception. A command should return true if the chain has completely handled the process. This notion is the basis of the Chain of Responsibility. Processing is handed off from command to command, until a command handles the command. If no process returns true, before reaching the end of the command sequence, the chain is assumed to have completed normally. A chain ends abnormally when any exception is thrown by a command. With Commons Chain, if a command throws an exception, the chain is broken. The exception, be it a runtime exception or application exception, will bubble up to the original caller of the chain. But many applications need explicit exception handling that is defined external to any commands. Commons Chain provides a facility for this using the Filter interface. Filter extends Command, adding a postprocess method. boolean postprocess(Context context,Exception exception) - execute any cleanup activities, such as releasing resources that were acquired during the execute() method of this Filter instance. Commons Chain guarantees that the postprocess method will be called if the Filter's execute method is called, regardless of any thrown exceptions. Like servlet filters, Chain Filters are executed in the order that they appear in the command sequence. Likewise,
  • 8. Apache Commons Chains in Spring Framework 2017 8 each Filter's postprocess method is called in reverse order. You can use this feature of Chain to implement exception handlers. Here's a Filter that traps exceptions that may occur in the sample chain. The Filter's execute method is called in sequence. However, the postprocess method is not called until the chain reaches its end or a command throws an exception. If an exception was raised, then the postprocess method handles the exception and returns true, indicating that the exception was handled. The chain does terminate at this point, but the exception is essentially caught and does not propagate further. If the postprocess method returns false, the exception bubbles up, causing abnormal termination of the chain. Example 2 : Example of adding Filter for Exception Handling in Chains using Java Program. Requirement : 1. IDE used : Eclipse 2. Java version used : 1.8 3. Above mentioned Jars. Steps to create & execute the project : 1. Create a java project Name – Spring_Chain_Filter. 2. Add all the above mentioned jar in class path. 3. Create a package under the src , name - com.rs.filter.sample 4. Create the below mentioned file and put to com.rs.filter.sample folder. 5. Run the main file “ChainDriver” to execute and view the output. 1. Chain-config.xml <catalog> <chain name="main-chain"> <command id="ExceptionHandler" className ="com.rs.filter.sample.ChainExceptionHandler"/> <command id="GetCommandInfo" className="com.rs.filter.sample.GetCommandInfo"/> </chain> </catalog> 2. GetCommandInfo.java package com.rs.filter.sample; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class GetCommandInfo implements Command { public boolean execute(Context ctx) throws Exception { System.out.println("Get command info"); return false; } } 3. ChainExceptionHandler.java package com.rs.filter.sample; import org.apache.commons.chain.Context; import org.apache.commons.chain.Filter; public class ChainExceptionHandler implements Filter { public boolean execute(Context context) throws Exception { System.out.println("Filter.execute() called."); return false; } public boolean postprocess(Context context,Exception exception) { if (exception == null) return false; System.out.println("Exception " + exception.getMessage() + " occurred."); return true; }
  • 9. Apache Commons Chains in Spring Framework 2017 9 } 4. ChainDriver.java package com.rs.filter.sample; import org.apache.commons.chain.Catalog; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; import org.apache.commons.chain.config.ConfigParser; import org.apache.commons.chain.impl.CatalogFactoryBase; import com.jadecove.chain.sample.SellVehicleContext; public class ChainDriver { private static final String CONFIG_FILE = "/com/rs/filter/sample/chain-config.xml"; private ConfigParser parser; private Catalog catalog; public ChainDriver() { parser = new ConfigParser(); } public Catalog getCatalog() throws Exception { if (catalog == null) { parser.parse(this.getClass().getResource(CONFIG_FILE)); } catalog = CatalogFactoryBase.getInstance().getCatalog(); return catalog; } public static void main(String[] args) throws Exception { ChainDriver loader = new ChainDriver(); Catalog sampleCatalog = loader.getCatalog(); Command command = sampleCatalog.getCommand("main-chain"); Context ctx = new SellVehicleContext(); command.execute(ctx); } } Output : Filter.execute() called. Get command info Apache commons chain in Spring framework So , you are now quite familiar with how the chain of commands actually works .Now , let us come to our main point of discussion that is the integration of Apache Commons Chains with the Spring framework. Apache APIs do make it simpler to configure, implement and execute multiple Chains of Responsibilities using spring framework. We will utilize the power that Apache offers and make it Spring friendly. Here configuring the chain is quite different, as we are using Spring Framework , because instead of relying on Apache way to configure chains, to make it consistent with all other application beans (classes) we’ll keep chain(s) configuration in Spring.  Explanation of the key interfaces of Apache commons chain in Spring framework Step 1: A chain-config.xml file The chain-config.xml file is somewhat different from the previously discussed chain-config.xml file. Here Spring framework giving us the reliability to use Apache’s bean org.apache.commons.chain.impl.ChainBase. So, instead of catalog we will use this spring bean configuration file , that will allows us to configure the chain. Here the chain “runchain” is configured as “org.apache.commons.chain.impl.ChainBase”, and have two Command classes, that implement “org.apache.commons.chain.Command” interface, wired in. <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util
  • 10. Apache Commons Chains in Spring Framework 2017 10 http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <bean name="runchain" class="org.apache.commons.chain.impl.ChainBase"> <constructor-arg> <util:list> <ref bean="Command1" /> <ref bean="Command2" /> </util:list> </constructor-arg> </bean> <bean name="Command1" class="com.chain.command.Command1"> <constructor-arg value="Command1...." /> <property name="message1" value =" Command1…"></property> </bean> <bean name="Command2" class="com.chain.command.Command2"> <constructor-arg value="Command2....." /> <property name="message2" value =" Command2…."></property> </bean> <bean id="chainRunner" class="com.chain.command.ChainRunner" /> </beans> The best practice is to keep Commands either stateless, or, if they have to have a state – immutable. If this practice is followed, these Commands can be safely reused throughout many chains (or even as stand-alone utilities). That is the reason, in configuration above, parameters are injected at Command’s creation time via constructor injection. Parameters can be injected either by Constructor injection or by Setter injection. Setter injection overrides the constructor injection. If we use both constructor and setter injection at the same time , IOC container will use the setter injection. So, better to use any one of them. Step 2 . An implementation of a command As already discussed in previous, chain of commands need Command classes for sequential flow of execution. This class inherits Command class and overrides execute method. In the example given bellow both the constructor and the setter injection are shown , but you need to use any one of them. public class Command1 implements Command { private String message1; //using constructor injection public Command1(String message1) { super(); this.message1 = message1; } //using setter injection public String getMessage1() { return message1; } public void setMessage1(String message1) { this.message1 = message1; } public boolean execute( Context context ) throws Exception { System.err.println( message1 ); return false; } } Step 3 : An implementation of interface BeanFactoryAware If a bean in spring implements BeanFactoryAware then that bean has to implement a method that is setBeanFactory. And when that bean is loaded in spring container, setBeanFactory is called. BeanFactoryAware belongs to the package org.springframework.beans.factory. BeanFactoryAware awares the bean for its BeanFactory. By implementing Spring’s “BeanFactoryAware” interface, at runtime ChainRunner will have a reference to a “beanFactory” which it is going to use to obtain a reference to the requested chain via “createChain” method. “ChainRunner” has an entry point which is a “runChain” method, that executes a chain by chain name (bean name in configuration file). For example, in the configuration shown above “runchain” name can be provided. It would ideally need to use a couple of custom runtime exceptions: e.g. ChainNotFoundException, IsNotChainException and ChainExecutionException, but we’ll keep it short here for clarity.
  • 11. Apache Commons Chains in Spring Framework 2017 11 Alternatively, to strong type chains a bit, “ChainRunner” could take a Map of chains with keys as chain names, and corresponding “ChainBase” chain objects as values. “ChainRunner” is pretty much everything that is needed in order to configure an Apache chain in Spring. public class ChainRunner implements BeanFactoryAware { private BeanFactory beanFactory; public void runChain( String chainName ) { try { createChain ( chainName ).execute( new ContextBase() ); } catch ( Exception exc ) { throw new RuntimeException( "Chain "" + chainName + "": Execution failed.", exc ); } } public void setBeanFactory( BeanFactory beanFactory ) throws BeansException { this.beanFactory = beanFactory; } protected ChainBase createChain( String chainName ) { return ( ChainBase ) this.beanFactory.getBean( chainName ); } } Step 4 : The execution of a chain Now the execution of chain of commands can be done using the below code . Here we need to create the chainRunner object to pass the factory and the chain name to execute the chain. The chain-config.xml can be loaded from anywhere like classpath location or from your local.  ClassPathXmlApplicationContext: For standalone java applications using XML based configuration.  FileSystemXmlApplicationContext: Similar to ClassPathXmlApplicationContext except that the xml configuration file can be loaded from anywhere in the file system. public class ChainDriver { public static void main(String[] args) throws Exception { System.out.println("start......"); ApplicationContext factory = new ClassPathXmlApplicationContext("/com/chain/command/chain-config.xml"); // ApplicationContext factory = new FileSystemXmlApplicationContext("C:UsersniveditamDesktopchain-config.xml"); ChainRunner chainRunner = new ChainRunner(); chainRunner.setBeanFactory(factory); chainRunner.runChain("runchain"); System.out.println("end......."); } } Step 5 : Passing value in Chain using ContextBase As discussed in previous ,ContextBase initialize the contents of this Context by copying the values from the specified Map. Any keys in map that correspond to local properties will cause the setter method for that property to be called. In addition to the minimal functionality required by the Context interface, this class implements the recommended support for Attribute-Property Transparency. This is implemented by analysing the available JavaBeans properties of this class (or its subclass), exposes them as key-value pairs in the Map, with the key being the name of the property itself. public boolean runChain( String chainName) { try { Context context = new ContextBase(); context.put("username", “Nivedita”); context.put("address1", “Kolkata”); createChain ( chainName ).execute( context ); } catch ( Exception ex) { ex.printStackTrace(); } }
  • 12. Apache Commons Chains in Spring Framework 2017 12 Once, this context object is passed in the chain , all values will be available in all the Command classes through context.get() . Mandatory Jars needed to execute the Apache chain-of-commands code with Spring Framework : 1. All previously mentioned Jars for Apache Common Chains. 2. Spring Jars – You don’t need to add all the Spring Jars to execute this code . Adding these jar will be enough. i) Spring-beans ii) Spring-context iii) Spring-core iv) Spring expression 3. For testing through JUnit (Optional). i) Juint ii) Spring-test iii) Spring-aop iv) Hamcrest-all Example 3 : Basic example of Apache commons chain using Spring framework. Requirement: 1. IDE used : Eclipse 2. Java version used : 1.8 3. Spring version used : 4.2 4. Above mentioned Jars. Steps to create & execute the project: 1. Create a java project Name – Spring_Chain. 2. Add all the above mentioned jar in class path. 3. Create a package under the src , name - com.chain.command 4. Create the below mentioned file and put to com.chain.command folder. 5. Run the main file “ChainDriver” to execute and view the output. 1. Chain-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <bean name="runchain" class="org.apache.commons.chain.impl.ChainBase"> <constructor-arg> <util:list> <ref bean="Command1" /> <ref bean="Command2" /> </util:list> </constructor-arg> </bean> <bean name="Command1" class="com.chain.command.Command1"> <constructor-arg value="Command1...." /> </bean> <bean name="Command2" class="com.chain.command.Command2"> <constructor-arg value="Command2....." /> </bean> <bean id="chainRunner" class="com.chain.command.ChainRunner" /> </beans> 2. Command1.java package com.chain.command; import org.apache.commons.chain.Command;
  • 13. Apache Commons Chains in Spring Framework 2017 13 import org.apache.commons.chain.Context; public class Command1 implements Command { private String message1; public Command1(String message1) { super(); this.message1 = message1; } public boolean execute( Context context ) throws Exception { System.err.println( message1 ); return false; } } 3. Command2.java package com.chain.command; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class Command2 implements Command { private String message2; public Command2(String message2) { super(); this.message2 = message2; } public boolean execute( Context context ) throws Exception { System.err.println( message2 ); return false; } } 4. ChainDriver.java package com.chain.command; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ChainDriver { public static void main(String[] args) throws Exception { System.out.println("Chain start......"); ApplicationContext factory = new ClassPathXmlApplicationContext("/com/chain/command/chain- config.xml"); ChainRunner chainRunner = new ChainRunner(); chainRunner.setBeanFactory(factory); chainRunner.runChain("runchain"); System.out.println("Chain end......."); } } 5. ChainTest.java (Optional) package com.chain.command; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class ) @ContextConfiguration( locations={ "/com/chain/command/chain-config.xml"} ) public class ChainTest { @Resource ChainRunner chainRunner; @Test public void driveTheChain() { System.out.println("Starting up... [Ok]"); chainRunner.runChain( "runchain" ); System.out.println("Finised... [Ok]");
  • 14. Apache Commons Chains in Spring Framework 2017 14 } } Output : Chain start...... Command1.... Command2..... Chain end....... Apache Commons Chain in Spring MVC Framework Using the Apache Commons chain in Spring MVC Framework is quite similar to the previously discussed Apache Commons chain in spring framework. There is no such huge difference in Apache Commons Chain architecture or configuration except the Spring Mvc Configuration. Controller : @Controller is a specific type of component, used in MVC applications and mostly used with RequestMapping annotation. Many applications use implementations of the Controller pattern to field user requests. A controller as a component that "interacts with a client, controlling and managing the handling of each request." .Often, an implementation of the Controller pattern will in turn use the Command pattern or Chain of Command pattern. In controller we will write a method that will map to a url , by this url the execution will be start up. @RequestMapping(value = "/ChainOfCommands/runchain", method = RequestMethod.GET, headers = "Accept=application/json") public void runchain(HttpServletRequest request) { } Service : @Service is used to indicate that a class is a Service. Usually the business facade classes that provide some services are annotated with this. In service layer we will define the chainrunner class , that will responsible for executing the command classes. @Service public class ChainRunner implements BeanFactoryAware { } Commands Class : Concept of Command classes is same as of previous. All the Command Classes should be kept in a different package for better practice. Chain-Config.xml: Concept of Command classes is same as of previous. So, we need to: 1. Create a Controller. 2. Add a Handler for our Request to the Controller. 3. Create a Request and pass it to the Controller. 4. Create a Chain service that will do all the business implementation. 5. Create Sequential execution of Chain of commands 6. Confirm that the Request returns the expected Response.
  • 15. Apache Commons Chains in Spring Framework 2017 15 Fig 2: Execution flow of Apache Commons Chain in Spring MVC Framework Example 4 : Creating a API using Apache Commons Chain in Spring MVC Framework . Requirement: 1. IDE used : Eclipse 2. Java version used : 1.8 3. Spring version used : 4.2 4. Above mentioned Jars with the additional 2 jar – Spring-web & Spring-webmvc Steps to create & execute the project: 1. Create a dynamic java project Name – SpringMVC_chain. 2. Add all spring jar and the above mentioned jar in class path. 3. Add the Spring-servlet.xml & web.xml under WEB-INF 4. Create a package under the src , name - com.chain.Controller, put the ChainController class there. 5. Create a package under the src , name - com.chain.Service. put the ChainRunnerService class there. 6. Create a package under the src , name com.chain.Command folder. Add all the Command classes. 7. Keep the chain-config.xml file under the src. 8. Start the server. 9. Hit the API url using browser/rest client. The project structure should look like the below structure – 1. CommandA.java
  • 16. Apache Commons Chains in Spring Framework 2017 16 package com.chain.Commands; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class CommandA implements Command { private String message; public CommandA( String message ) { this.message = message; } public boolean execute( Context context ) throws Exception { System.out.println("CommandA....."+message); return false; } } 2. CommandB.java package com.chain.Commands; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class CommandB implements Command { private String message; public CommandB( String message ) { this.message = message; } public boolean execute( Context context ) throws Exception { System.err.println("CommandB....."+message); return false; } } 3. CommandC.java package com.chain.Commands; import org.apache.commons.chain.Command; import org.apache.commons.chain.Context; public class CommandC implements Command { private String message; public CommandC( String message ) { this.message = message; } public boolean execute( Context context ) throws Exception { System.out.println("CommandC......"+message); return false; } } 4. ChainController.java package com.chain.Controller; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.chain.Service.ChainRunnerService;
  • 17. Apache Commons Chains in Spring Framework 2017 17 @RestController public class ChainController { @Autowired ChainRunnerService chainRunnerService; @RequestMapping(value = "/ChainOfCommands/runchain", method = RequestMethod.GET, headers = "Accept=application/json") public void runchain(HttpServletRequest request) { System.out.println("start......"); ApplicationContext factory = new ClassPathXmlApplicationContext("chain-config.xml"); chainRunnerService.setBeanFactory(factory); chainRunnerService.runChain("mvcchain"); System.out.println("end......."); } } 5. ChainRunnerService.java package com.chain.Service; import org.apache.commons.chain.impl.ChainBase; import org.apache.commons.chain.impl.ContextBase; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.stereotype.Service; @Service public class ChainRunnerService implements BeanFactoryAware { private BeanFactory beanFactory; public void runChain( String chainName ) { try { createChain ( chainName ).execute( new ContextBase() ); } catch ( Exception exc ) { throw new RuntimeException( "Chain "" + chainName + "": Execution failed.", exc ); } } public void setBeanFactory( BeanFactory beanFactory ) throws BeansException { this.beanFactory = beanFactory; } protected ChainBase createChain( String chainName ) { return ( ChainBase ) this.beanFactory.getBean( chainName ); } } 6. Chain-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <bean name="mvcchain" class="org.apache.commons.chain.impl.ChainBase"> <constructor-arg> <list> <ref bean="commandA" /> <ref bean="commandB" /> <ref bean="commandC" /> </list> </constructor-arg> </bean>
  • 18. Apache Commons Chains in Spring Framework 2017 18 <bean name="commandA" class="com.chain.Commands.CommandA"> <constructor-arg value="commandA" /> </bean> <bean name="commandB" class="com.chain.Commands.CommandB"> <constructor-arg value="commandB" /> </bean> <bean name="commandC" class="com.chain.Commands.CommandC"> <constructor-arg value="commandC" /> </bean> <bean id="chainRunner" class="com.chain.Service.ChainRunnerService" /> </beans> Run & Execution : Make a HTTP GET Request with http://localhost:8080/SpringMVCchain/ChainOfCommands/runchain Console Output : start...... CommandA.....commandA CommandB.....commandB CommandC......commandC end....... Limitation Chain is not a full workflow system. It does not have sophisticated flow of control between branches of chains or looping. However, it is also easier to get started with than most workflow systems and you can easily refactor existing code to fit within it. Editing the XML file to change the sequence of commands or alter the parameters passed to a command is also well within the realm of what many end users can do themselves without minimal instruction. ******KEY NOTES******  This framework, developed under the community umbrella of the Jakarta Commons project  Key package - org.apache.commons.chain  Classes - Command, ContextBase, Filter  Main classes – ContextBase  Exception handling and post process – Filter  Utility classes for loading - Catalog, config.ConfigParser, impl.CatalogFactoryBase  Used as a glue to bind commands - ContextBase  Implementations of Context must also implement all of the required and optional contracts of the java.util.Map interface. Reference http://commons.apache.org/proper/commons-chain/ https://commons.apache.org/proper/commons-chain/apidocs/