How to implement a dynamic chain of responsibility in Java? -


i have set of requirements on business logic validation:

  1. each independent step of validation must separated;
  2. the order of these steps can defined administrator;
  3. steps can disabled.
  4. each validation step isn't user-defined - i.e. code is compiled.

so thought of implementing dynamic chain of responsibility, that'd load steps order , classnames table, instantiate them class.forname(). i'm not fond of storing classname in table lead potential issues (refactoring name of validator, instance, break code). do:

enter image description here

of course, more flexible solution has be, more complex be. still, i'd know if there's way garantee above requirements without storing class names in table?

you don't need reinvent wheel. use commons chain apache start point , mix custom solution. provides elegant , easy way solve problem. save configuration xml file (catalog) , load db if want.

here example:

to see how commons chain works, let's start contrived example: business process employed purveyors of pre-owned vehicles (a.k.a., used car salespeople). here steps compose sales process:

get customer information test-drive vehicle negotiate sale arrange financing close sale 

now suppose wanted model flow using template method pattern. create abstract class--defining algorithm--that looks this:

    public abstract class sellvehicletemplate {         public void sellvehicle() {             getcustomerinfo();             testdrivevehicle();             negotiatesale();             arrangefinancing();             closesale();         }      public abstract void getcustomerinfo();     public abstract void testdrivevehicle();     public abstract void negotiatesale();     public abstract void arrangefinancing();     public abstract void closesale();    } 

now let's see how implement process using commons chain. first, download commons chain. can grab latest nightly download .zip or .tar file, or can acquire up-to- date code checking out commons chain module cvs or subversion source repositories. extract archive, placing commons-chain.jar file on classpath.

to implement business process using commons chain, implement each step in process class has single public "do all" method named execute(). traditional usage of command pattern. here's simple implementation of "get customer information" step.

package com.jadecove.chain.sample;  import org.apache.commons.chain.command; import org.apache.commons.chain.context;  public class getcustomerinfo implements command {     public boolean execute(context ctx) throws exception {         system.out.println("get customer info");         ctx.put("customername","george burdell");         return false;     } } 

for illustration purposes, class doesn't much. however, store customer's name in context. context object provides glue between commands. time being, think of context nothing more hash table can stuff values into, , pull values out of, key. subsequent commands can access data. testdrivevehicle, negotiatesale, , arrangefinancing command classes simple implementations print out command do.

package com.jadecove.chain.sample;  import org.apache.commons.chain.command; import org.apache.commons.chain.context;  public class testdrivevehicle implements command {     public boolean execute(context ctx) throws exception {         system.out.println("test drive vehicle");         return false;     } }  public class negotiatesale implements command {     public boolean execute(context ctx) throws exception {         system.out.println("negotiate sale");         return false;     } }  public class arrangefinancing implements command {     public boolean execute(context ctx) throws exception {         system.out.println("arrange financing");         return false;     } } 

the closesale implementation uses context extract customer's name, set in getcustomerinfo command.

package com.jadecove.chain.sample;  import org.apache.commons.chain.command; import org.apache.commons.chain.context;  public class closesale implements command {     public boolean execute(context ctx) throws exception {         system.out.println("congratulations "                   +ctx.get("customername")             +", bought new car!");         return false;     } } 

now can define process sequence or "chain of commands."

package com.jadecove.chain.sample;  import org.apache.commons.chain.impl.chainbase; import org.apache.commons.chain.command; import org.apache.commons.chain.context; import org.apache.commons.chain.impl.contextbase;  public class sellvehiclechain extends chainbase {     public sellvehiclechain() {         super();         addcommand(new getcustomerinfo());         addcommand(new testdrivevehicle());         addcommand(new negotiatesale());         addcommand(new arrangefinancing());         addcommand(new closesale());     }     public static void main(string[] args) throws exception {         command process = new sellvehiclechain();         context ctx = new contextbase();         process.execute(ctx);     } } 

this example shows how can use commons chain api create , execute sequence of commands. of course, every new piece of software written in java these days, commons chain can configured via xml file. applying capability "sell vehicle" process, can define sequence of commands in xml file. canonical name file chain-config.xml.

<catalog>   <chain name="sell-vehicle">     <command   id="getcustomerinfo"         classname="com.jadecove.chain.sample.getcustomerinfo"/>     <command   id="testdrivevehicle"         classname="com.jadecove.chain.sample.testdrivevehicle"/>     <command   id="negotiatesale"         classname="com.jadecove.chain.sample.negotiatesale"/>     <command   id="arrangefinancing"         classname="com.jadecove.chain.sample.arrangefinancing"/>     <command   id="closesale"         classname="com.jadecove.chain.sample.closesale"/>   </chain> </catalog> 

the chain configuration file can contain multiple chain definitions grouped catalogs. example, chain definition defined within default catalog. can, in fact, have multiple named catalogs within file, each own set of chains.

now, instead of defining sequence of commands done in sellvehiclechain, load catalog , retrieve named chain using classes provided commons chain.

package com.jadecove.chain.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;  public class catalogloader {     private static final string config_file =          "/com/jadecove/chain/sample/chain-config.xml";     private configparser parser;     private catalog catalog;      public catalogloader() {         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 {         catalogloader loader = new catalogloader();         catalog samplecatalog = loader.getcatalog();         command command = samplecatalog.getcommand("sell-vehicle");         context ctx = new sellvehiclecontext();         command.execute(ctx);     } } 

chain uses commons digester read , parse configuration file. use capability, need add commons digester .jar file classpath. used version 1.6 , had no problems. digester depends on commons collections (i used version 3.1), commons logging (version 1.0.4), , commons beanutils 1.7.0. need add these .jars classpath, well. after adding these .jar files classpath, catalogloader compiled , ran. output generated other 2 tests.

source: http://www.onjava.com/pub/a/onjava/2005/03/02/commonchains.html


Comments

Popular posts from this blog

Email notification in google apps script -

c++ - Difference between pre and post decrement in recursive function argument -

javascript - IE11 incompatibility with jQuery's 'readonly'? -