Sunday, October 21, 2012

Apache Common Chain Usage Made Easy


Apache Common Chain Usage - 

Tasks

1. create a class that executes the job. This class inherits Command class and overrides execute method.
 (execute method returns false for the execution chain to continue or true to stop the chain further processing)

2. Create a class that inherits ContextBase 
(it is a glue in the chain (between each command executor) .Command classes suck data from this glue )

3.Create a class inherits Filter and implement execute and postprocess method.
 (It is similar to command class, but used as a exception handler and fall back situation)

4.Write the chain xml file

5.Load the chain xml file in a web app by modifying web.xml. Add xml file path to application startup parameter and add commons chain listener, ChainLister  class
(Method 1 explained below)

6.Write client code to execute the chain where the Catalog will be an injected object or get the catalog object in a web application using by retrieving the value of catalog attribute from application context.

7. For adding a chain to struts 1.3 request processor, (section struts use)
- Create a class inheriting command. 
(Use the ServletActionContext as the context within execute method to get the data.)
-Create xml section of the chain
-Create a xml file and add it as an init parameter of ActionServlet
(See Struts 1.3 package example app named cookbook)


Key Classes -
Package - org.apache.commons.chain
 
Classes - 
- Command , ContextBase (main classes), Filter (user for exception handling and post process)
- Catalog, config.ConfigParser, impl.CatalogFactoryBase (utility classes for loading)
 
ContextBase (used as a glue to bind commands)  

 Sample implementation - 

Command -

public class ProfileCheck implements Command {

    public Profile newProfile(Context context) { return new Profile(); }

    public boolean execute(Context context) throws Exception {
        Object profile = context.get(Profile.PROFILE_KEY);
        if (null == profile) {
            profile = newProfile(context);
            context.put(Profile.PROFILE_KEY, profile);
        }
        return false;
    }
}
 

Context - 

public class MailReaderContext extends ContextBase {Prop
    public static String LOCALE_KEY = "locale";
    private Locale locale;
    public Locale getLocale() {
        return locale;
    }
    public void setLocale(Locale locale) {
        this.locale = locale;
    }
} 

Client code (method) - 

boolean executeCatalogCommand (Catalog sampleCatalog) { 
Command command = sampleCatalog.getCommand("LocaleChange");
Context ctx = new MailReaderContext();
command.execute(ctx); 
}

Filter (extra for exception handling)- 

public class SellVehicleExceptionHandler 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;
 }
}

Format of chain config file - 

<?xml version="1.0" ?>
<catalog>
 
 <chain name="LocaleChange">
    <command 
      className="org.apache.commons.chain.mailreader.commands.ProfileCheck"/>
    <command 
      className="org.apache.commons.chain.mailreader.commands.LocaleChange"/>
  </chain> 
 
 <chain name="sell-vehicle">
  <command   id="ExceptionHandler"
     className =
           "com.jadecove.chain.sample.SellVehicleExceptionHandler"/>
  <command   id="GetCustomerInfo"
      className="com.jadecove.chain.sample.GetCustomerInfo"/> 
 </chain>
  <command 
    name="LogonUser" 
    className="org.apache.commons.chain.mailreader.commands.LogonUser"/>
  </catalog>

Loading catalog  :

Method 1 (loading in web application) - 

In web application, load by adding thus listener to web.xml
<!-- Commons Chain listener to load catalogs  -->
<context-param>
  <param-name>org.apache.commons.chain.CONFIG_CLASS_RESOURCE</param-name>
  <param-value>resources/catalog.xml</param-value>
</context-param>
<listener>
  <listener-class>org.apache.commons.chain.web.ChainListener</listener-class>
</listener>
 
 Access in code as -
Catalog catalog = (Catalog) request.getSession()
        .getServletContext().getAttribute("catalog");

Method 2 (general)-

new ConfigParser().parser.parse(this.getClass().getResource("/com/jadecove/chain/sample/chain-config.xml"));
Catalog catalog = CatalogFactoryBase.getInstance().getCatalog();


Struts use - 

Command class - 

public class CheckUser implements Command {

  public boolean execute(Context ctx) throws Exception {
    ServletActionContext context = (ServletActionContext) ctx;
    Object user = context.getSessionScope().get(Constants.USER_KEY);
    if (user == null &&
        context.getParameterMap().containsKey("checkUser")) {
 HttpServletResponse response = 
        ((ServletActionContext) ctx).getResponse();
 response.sendError(403, "User not logged in.");
 return true;
    }
    return false;
  }

}
 

xml section  - (custom-chain-config.xml)

<?xml version="1.0" ?>
<catalog name="struts">
    <chain name="servlet-standard-preprocess">
        <command className="com.jadecove.chain.commands.CheckUser"/>
    </chain>
</catalog> 

 Add to web.xml 

<!-- Action Servlet Configuration -->
<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>
      org.apache.struts.action.ActionServlet
    </servlet-class>
    <init-param>
        <param-name>config</param-name>
        <param-value>
            /WEB-INF/struts-config.xml,
            /WEB-INF/struts-config-registration.xml
        </param-value>
    </init-param>
    <init-param>
        <param-name>chainConfig</param-name>
        <param-value>
            /WEB-INF/chain-config.xml, 
            /WEB-INF/custom-chain-config.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>



Figure 1

No comments:

Post a Comment