有點標題黨的嫌疑
本文不涉及工作流中的環節(step)、條件(conditions)、循環(loops)、分支(spilts)、合併(joins)、角色(roles)等等。
不涉及工作流。
呵呵,說白了, 就是在責任鏈中加入腳本控制。
擴展自apache common chain:
http://commons.apache.org/chain/
比如有如下chain:描述我工作日的生活:早餐,去公司,工作,午餐, 工作, 回家
<catalog> <chain name="my working day life"> <command id="breakfast" className="co.command.BreakfastCommand" /> <command id="go-to-company" className="co.command.GotoCompanyCommand" /> <command id="work" className="co.command.WorkCommand" /> <command id="lunch" className="co.command.LunchCommand" /> <command id="work" className="co.command.WorkCommand" /> <command id="go-home" className="co.command.GohomeCommand" /> </chain> </catalog>
如果是假期, 那我的生活或許是這樣的: 早餐,出去high, 回家
<catalog> <chain name="my holiday life"> <command id="breakfast" className="co.command.BreakfastCommand" /> <command id="play" className="co.command.PlayCommand" /> <command id="go-home" className="co.command.GohomeCommand" /> </chain> </catalog>
好了, 我現在有一個需求, 需要在chain的配置中, 加入腳本功能, 以控制command是否應該執行。
如果有了這個功能, 以上的兩個chain就可以合併爲一個:
<catalog> <chain name="my working day life"> <command id="breakfast" className="co.command.BreakfastCommand" /> <script expression="context.isHoliday()"> <command id="play" className="co.command.PlayCommand" /> </script> <script expression="!context.isHoliday()"> <command id="go-to-company" className="co.command.GotoCompanyCommand" /> <command id="work" className="co.command.WorkCommand" /> <command id="lunch" className="co.command.LunchCommand" /> <command id="work" className="co.command.WorkCommand" /> </script> <command id="go-home" className="co.command.GohomeCommand" /> </chain> </catalog>
有了流程控制, 實現了command的流轉。
具體如何實現的呢?
我爲沒一個command增加了一個expression屬性(即腳本內容):
在<script>...</script>節點包含的每個command中,有相同的expression屬性.
比如:
<script expression="!context.isHoliday()"> <command id="go-to-company" className="co.command.GotoCompanyCommand" /> <command id="work" className="co.command.WorkCommand" /> <command id="lunch" className="co.command.LunchCommand" /> <command id="work" className="co.command.WorkCommand" /> </script>
這是個command,每個command的expression值都爲:"!context.isHoliday()"
來一個command的基類:
在運行商業邏輯(action)之前, 運行一下expression, 如果爲true,就執行action, 否則, 繼續下一個command:
public abstract class BaseCommand implements org.apache.commons.chain.Command
{
private String expression;
private ScriptEngine scriptEngine;
public final boolean execute(Context context) throws Exception
{
if(this.isRunable(context))
{
return this.action(context);
}
return false;
}
private boolean isRunable(Context context)
{
if(!StringUtils.hasText(this.expression))
return true;
return ((Boolean)scriptEngine.run(this.expression, context)).booleanValue();
}
public void setScriptEngine(ScriptEngine scriptEngine)
{
this.scriptEngine = scriptEngine;
}
public String getExpression()
{
return expression;
}
public void setExpression(String expression)
{
this.expression = expression;
}
public abstract boolean action(Context context) throws Exception;
}
ScriptEngine是一個script 引擎接口:
public interface ScriptEngine
{
public Object run(String express, Object context);
}
給一個groovy的實現:
public class GroovyExpressionEngine implements ScriptEngine
{
public Object run(String express, Object context)
{
ClassLoader cl = GroovyExpressionEngine.class.getClassLoader();
GroovyClassLoader groovyCl = new GroovyClassLoader(cl);
Class groovyClass = groovyCl.parseClass(express);
Script sc;
try
{
sc = (Script)groovyClass.newInstance();
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
Binding binding = new Binding();
binding.setVariable("context", context);
sc.setBinding(binding);
return sc.run();
}
}
Game over!