开始使用Commons Chain 运用讲解(3)
清单10
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使用commons digester来读取和解析配置文件。因此你需要将commons digester.jar加入classpath中。我使用了1.6版本并且工作得很好。digester使用了commons collectios(我使用的版本是3.1),commons logging(版本
1.0.4),commons beanutils(1.7.0),因此你也需要将它们的jar文件加入classpath中。在加入这些jar后,catalogloader就可以被编译和运行,它的输出和另外两个测试完全相同。
现在你可以在xml文件中定义链,并可以在程序中得到这个链(别忘了链也是命令),这样扩展的可能性和程序的灵活性可以说是无限的。假设过程"安排财务"实际上由一个完全分离的商业部门处理。这个部门希望为这种销售建立自己的工作流程。chain提供了嵌套链来实现这个要求。因为链本身就是命令,因此你可以用指向另一个链的引用替换一个单一用途的命令。下面是增加了新流程的链的定义:
清单11
<catalog name="auto-sales">
<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
classname="org.apache.commons.chain.generic.lookupcommand"
catalogname="auto-sales"
name="arrange-financing"
optional="true"/>
<command id="closesale"
classname="com.jadecove.chain.sample.closesale"/>
</chain>
<chain name="arrange-financing">
<command id="arrangefinancing"
classname="com.jadecove.chain.sample.arrangefinancing"/>
</chain>
</catalog>
commons chain提供了一个常用的命令lookupcommand来查找和执行另一个链。属性optional用于控制当指定的嵌套链没有找到时如何处理。optional=true时,即使链没找到,处理也会继续。反之,lookupcommand将抛出illegalargumentexception,告知指定的命令未找到。
在下面三种情况下,命令链将结束:
1.命令的execute方法返回true
2.运行到了链的尽头
3.命令抛出异常
当链完全处理完一个过程后,命令就返回true。这是责任链模式(chain of responsibility)的基本概念。处理从一个命令传递到另一个命令,直到某个命令(command)处理了这个命令。如果在到达命令序列尽头时仍没有处理返回true,也假设链已经正常结束。
当有命令抛出错误时链就会非正常结束。在commons chain中,如果有命令抛出错误,链的执行就会中断。不论是运行时错误(runtime exception)还是应用错误(application exception),都会抛出给链的调用者。但是许多应用都需要对在命令之外定义的错误做明确的处理。commons chain提供了filter接口来满足这个要求。filter继承了command,添加了一个名为postprocess的方法。
public boolean postprocess(context context, exception exception);
只要filter的execute方法被调用,不论链的执行过程中是否抛出错误,commons chain都将保证filter的postprocess方法被调用。和servlet的过滤器(filter)相同,commons chain的filter按它们在链中的顺序依次执行。同样,filter的postprocess方法按倒序执行。你可以使用这个特性实现自己的错误处理。下面是一个用于处理我们例子中的错误的filter:
清单12
package com.jadecove.chain.sample;
import org.apache.commons.chain.context;
import org.apache.commons.chain.filter;
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;
}
}
filter在配置文件中的定义就和普通的命令(command)定义相同:
清单13
<chain name="sell-vehicle">
<command id="exceptionhandler"
classname =
"com.jadecove.chain.sample.sellvehicleexceptionhandler"/>
<command id="getcustomerinfo"
classname="com.jadecove.chain.sample.getcustomerinfo"/>
filter的execute方法按定义的序列调用。然而,它的postprocess方法将在链执行完毕或抛出错误后执行。当一个错误被抛出时,postprocess方法处理完后会返回true,表示错误处理已经完成。链的执行并不会就此结束,但是本质上来说这个错误被捕捉而且不会再向外抛出。如果postprocess方法返回false,那错误会继续向外抛出,然后链就会非正常结束。
让我们假设arrangefinancing因为用户信用卡损坏抛出错误。sellvehic
leexceptionhandler就能捕捉到这个错误,程序输出如下:
filter.execute() called.
get customer info
test drive the vehicle
negotiate sale
exception bad credit occurred.
结合了过滤器(filter)和子链技术后,你就可以造型很复杂的工作流程。
[来源 www.iocblog.net]
commons chain是一个很有前途的框架,现在仍在开发,新的功能被频繁地添加到其中。在下一篇关于commons chain的文章中,我们将研究struts 1.3中是如何使用commons chain的。
struts 1.3中用完全使用commons chain的类替换了原来的处理http请求的类。如果你以前自己定制过struts的请求处理(request processor),你将发现处理这个问题时commons chain为程序带来了很好的灵活性。
Tag: jakarta
文章整理:iocblog
版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。