山寨版工作流:groovy控制的責任鏈


有點標題黨的嫌疑
本文不涉及工作流中的環節(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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章