<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Terry.Li-彬

    虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks
    Revision History
    Revision 0.1 2009/06/29
    增加了前3章的內容

    Abstract

    這篇文章主要是介紹了jBPM 4.0的基礎架構,以及通過一個簡單的例子來讓大家知道怎么應用jBPM. 為什么選擇4.0版本呢?以后的主流版本應該是4.0版本的,所以直接寫4.0版本的了.

    在默認情況下,jBPM包里有個jbpm.cfg.xml,這個就是他的配置文件,我們先看下它的內容.

    												
    														
    <jbpm-configuration>
    <import resource="jbpm.default.cfg.xml" />
    <import resource="jbpm.tx.jta.cfg.xml" />
    <import resource="jbpm.jpdl.cfg.xml" />
    <import resource="jbpm.identity.cfg.xml" />
    <import resource="jbpm.jobexecutor.cfg.xml" />
    </jbpm-configuration>

    這里,我們再繼續看下jbpm.default.cfg.xml,看下配置文件到底是長啥樣.

    												
    														
    <process-engine-context>
    <repository-service />
    <repository-cache />
    <execution-service />
    <history-service />
    <management-service />
    <identity-service />
    <task-service />
    <hibernate-configuration>
    <cfg resource="jbpm.hibernate.cfg.xml" />
    </hibernate-configuration>
    ...........
    </process-engine-context>

    <transaction-context>
    <repository-session />
    <db-session />
    <message-session />
    <timer-session />
    <history-session />
    <mail-session>
    <mail-server>
    <session-properties resource="jbpm.mail.properties" />
    </mail-server>
    </mail-session>
    </transaction-context>

    這個配置文件主要包含了"process-engine-context'和 'transaction-context'的配置.

    我們知道,現在都是講究Dependency Inject (Inversion of Control),那么,我們這里到底是哪個類來實現repository-service呢?那配置mail-session又是怎么實例化的呢? 我們先來看下jBPM的IOC實現機制.

    首先是Context接口,你可以從這里存儲,獲得對象.它的接口很簡單.

    												  Object get(String key);
    <T> T get(Class<T> type);

    Object set(String key, Object value);

    你看可以從Context中獲取到組件,對于IOC容器來說,一般情況下都會提供一種加載的方式,比如從xml文件進行加載、從資源文件進行加載。

    Jbpm4是通過WireParser來解析xml,然后創建并把對象存放在WireContext. WireContext這個類負責存放,提取對象,內部用一個Map來存儲已經創建的對象實例,可以簡單得把他看成是IOC的一個實現類. 從WireContext的javadoc,我們可以看出,他主要是跟WireDefinition, Descriptor打 交道. WireContext里面 包含了一個WireDefinition,而WireDefinition里面包含了一系列的Descriptor.每個Descriptor負責創建和 初始化該對象. 比如我們可以看到IntegerDescriptor, FloatDescriptor, ObjectDescriptor等等. 我們來看下Descriptor的接口:

    												
    														
    /**
    * constructs the object.
    * @param wireContext {@link WireContext} in which the object is created. This is also the {@link WireContext}
    * where the object will search for other object that may be needed during the initialization phase.
    * @return the constructed object.
    */
    Object construct(WireContext wireContext);

    /**
    *called by the WireContext to initialize the specified object.
    */
    void initialize(Object object, WireContext wireContext);

    Descriptor對象的創建可以直接通過Java對象的實例化,比如(new IntegerDescriptor(..)),也可以通過xml的配置文件來實現.可以說我們更經常用xml來配置,所以就有了Binding的概念. Binding類最主要的任務就是把XML DOM 到Java對象的轉換. Bindings是把Binding歸類了一下而已. 以下是Binding的接口.

    												
    														
    public interface Binding {
    String getCategory();

    /** does this binding apply to the given element? */
    boolean matches(Element element);

    /** translates the given element into a domain model java object.
    * Use the parse to report problems.
    */
    Object parse(Element element, Parse parse, Parser parser);
    }

    如果想看實現,我們可以看下IdentityServiceBinding, RepositoryServiceBinding等等.這里注意下,在jBPM的實現當中,WireDescriptorBinding是根據tagName來解析的. 所以,從jBPM的xml配置文件,到ProcessEngine對象的構建,是這樣的一個流程.

    												 jbpm.cfg.xml –>  jBPMConfigurationParser ->  Binding –>  Descriptor --> WireContext
    										

    或者更清楚的,我們可以看下下面這張圖[ 1].

    我們不妨也看下ConfigurationTest測試.

    												
    public void testConfigurationServices() {
    ProcessEngine processEngine = new Configuration()
    .setXmlString(
    "<jbpm-configuration>" +
    " <process-engine-context>" +
    " <repository-service />" +
    " <execution-service />" +
    " <management-service />" +
    " </process-engine-context>" +
    "</jbpm-configuration>"
    )
    .buildProcessEngine();
    assertNotNull(processEngine);
    assertNotNull(processEngine.getExecutionService());
    assertNotNull(processEngine.getManagementService());
    }

    Configuration 類是jBPM的入口,你可以從 Configuration類中創建ProcessEngine,而從ProcessEngine中獲取到RepositoryService, ExecutionService, TaskService等等. Configuration類里有兩個實現類,一個是JbpmConfiguration,這是默認的jBPM自帶的Configuration解析器, 另外一個是SpringConfiguration,這個是jBPM和Spring的集成. 在這里,我們就只看下JbpmConfiguration的實現,在JbpmConfiguration類里,我們可以看到他是這么去調用Parser來 解析xml的.

    												
    protected void parse(StreamInput streamSource) {
    isConfigured = true;
    JbpmConfigurationParser.getInstance()
    .createParse()
    .pushObject(this)
    .setStreamSource(streamSource)
    .execute()
    .checkErrors("jbpm configuration " + streamSource);
    }

    在這里,我們可以看到,jbpm的配置文件是有兩個元素組成的,一個是process-engine-context,另外一個是transaction-context. 其中process-engine-context里面的元素是包括了對外發布的服務, 比如repository-service, execution-service等等. 而transaction-context則包括了他的內部真正實現,比如repository-service對應repository-session. 也可以簡單的把repository-servie看做是API, repository-session看做是SPI. 這樣做的好處是,SPI的實現,對API一點影響都沒有,很大程度上提供了一個容易集成的特性.

    說到這里,應該對jBPM的IOC介紹的差不多了.我自己在用JBoss IDM project[2]來實現jBPM的Identity module時.需要增加如下的配置.

    												
    <jbpm-configuration>
    <process-engine-context>
    <jboss-idm-identity-session-factory jndi="java:/IdentitySessionFactory" />
    </process-engine-context>
    <transaction-context>
    <jboss-idm-identity-session realm="realm://JBossIdentity" />
    </transaction-context>
    </jbpm-configuration>

    于是,我需要增加以下的類來完成對象的創建和實例化. JbossIdmIdentitySessionFactoryBinding,JbossIdmIdentitySessionFactoryDescriptor,JbossIdmIdentitySessionBinding, JbossIdmIdentitySessionDescriptor 然后,在jbpm.wire.bindings.xml里面注冊我們新加的Binding. 從上面我們所說的,不難看出本身這個IOC的實現機制也是很簡單的,而且也很容易擴展,如果說到時候和Spring, JBoss MC等IOC容器的集成也是很方便的.

    這里,我們看下jBPM-PVM概念和架構,這也是jBPM整個項目的核心所在.

    PVM (Process Virtual Machine), 主要是想作為一個開發平臺,在這個平臺上,可以很方便的開發工作流,服務編制(orchestration),BPM等等.就比如 說jPDL這套語法的內部實現就是基于PVM的.將來基于PVM可以開發一個符合WS-BPEL 2.0的模塊. PVM可以簡單的看成是一個狀態機. 我們接下去看下jBPM里面的幾個重要概念.

    Command 概念的引入,主要是想對所有的操作做一個封裝. 可以說上面每個Service的方法的實現都是通過實現一個Command來操作,然后通過CommandService調用到后面具體的實現. 我們先來看下Command的接口.

    														public interface Command<T> extends Serializable {
    T execute(Environment environment) throws Exception;
    }

    很簡單,很典型的Command模式.

    我們接下來看CommandService接口,顧名思義,他主要是負責來執行Command(s)的操作.所以其他Service的實現都是通過CommandService來調用到后面的實現,可以把CommandService 看做一個橋梁的作用.看一下CommandService的接口.

    														public interface CommandService {
    /**
    * @throws JbpmException if command throws an exception.
    */
    <T> T execute(Command<T> command);
    }

    CommandService 還有一個特性,就是可以配置Interceptor,比如事務就是在這一Service中來配置.看下CommandService的配置.

    														    <command-service>
    <retry-interceptor />
    <environment-interceptor />
    <standard-transaction-interceptor />
    </command-service>

    這里,在執行真正的CommandServiceImpl之前,會先之前retry-Interceptor,environment-interceptor等等.這里的Interceptor的順序是跟配置的順序一致的. 比如這樣的配置,那就是retry-interceptor在environment-interceptor之前執行. 我們看下面這個圖.

    ProcessDefinition是一個定義好的工作流程. OpenProcessDefinition里面包含了啟始的Activity. 流程的走向是通過Activity的流向來組成的. Transition就是用來連接Activity而后來構成一個流程的. 一個工作流的工作引擎,最基本的兩個功能:一個是設計好當前的工作流程.第二個是有個東西需要來體現當前走到流程的哪一步,那么PVM中的Execution API就是這個作用. 至于最后一個Event,就是你可以定義一些事件,比如當流程進入到某一個Activity的時候,促發email. Event和Activity最大的區別在于Event本身不會構成對流程走向的改變.

    我們先看下ActivityBehaviour的接口.

    														public interface ActivityBehaviour extends Serializable {
    void execute(ActivityExecution execution) throws Exception;
    }

    就是到這個Activity,需要執行的操作都在execute方法里. 還有一種ActivityBehaviour,就是屬于wait state,也就是會停留在這個節點上, 需要外部的一些觸發,才會繼續執行下去,這種情況,需要實現的接口就是ExternalActivityBehaviour, 接口如下.

    														public interface ExternalActivityBehaviour extends ActivityBehaviour { 
    //handles an external trigger.
    void signal(ActivityExecution execution, String signalName, Map<String, ?> parameters) throws Exception;
    }

    Wait State (也就是實現ExternalActivityBehaviour)的促發,是通過Transition來完成的,來看下Transition這個接口.

    														public interface Transition extends ObservableElement {
    /** the activity from which this transition leaves. */
    Activity getSource();

    /** the activity in which this transition arrives. */
    Activity getDestination();
    }

    在pvm中,也包括了對event的支持,event的接口如下.

    														public interface EventListener extends Serializable { 
    void notify(EventListenerExecution execution) throws Exception;
    }

    如我們之前所說的, ProcessDefinition是由Activity,Transition以及Event組成的,ProcessDefinition是由ProcessDefinitionBuilder 的API來創建.我們稍微看下這個API的使用.

    																ClientProcessDefinition definition = ProcessDefinitionBuilder.startProcess("jeffProcess")
    .startActivity("initial", new AutomaticActivity())
    .initial()
    .transition("first")
    .endActivity()
    .startActivity("first", new WaitStateActivity())
    .transition("end", "endSignal")
    .endActivity()
    .startActivity("end", new AutomaticActivity())
    .endActivity()
    .endProcess();

    這里,我們將利用PVM所提供的Model,來實現一個基本的工作流引擎.

    正如我們之前所說的,ActivityBehaviour是整個流程的定義核心所在,我們再看下它的API.

    														public interface ActivityBehaviour extends Serializable {    
    void execute(ActivityExecution execution) throws Exception;
    }

    當之行到ActivityBehaviour的時候,整個流程的走向完全是由他的execute()方法來決定. 比如你可以調用execution.end()來結束這個流程,或者調用execution.waitForSignal()進入一個等待狀態. 我們接下去來實現一個很簡單的ActivityBehaviour.

    														public class Display implements ActivityBehaviour {
    String message;

    public Display(String message) {
    this.message = message;
    }

    public void execute(ActivityExecution execution) {
    System.out.println(message);
    }
    }

    我們先用這個Display,來創建下面的process.


    														ClientProcessDefinition processDefinition = ProcessDefinitionBuilder.startProcess("helloworld")
    .startActivity("a", new Display("Hello"))
    .initial()
    .transition("b")
    .endActivity()
    .startActivity("b", new Display("World"))
    .endActivity()
    .endProcess();

    然后,你調用

    														processDefinition.startProcessInstance();

    就會得到如下的結果

    														Hello
    World

    我們這個Display的節點就是采用的隱式execution執行方法.

    外部節點就是代表著,這個活動還需要系統外部的配合,比如說人工的配合才能使得這個流程繼續下去.我們一般稱這種的節點為 Wait State. 因為他需要一直等待,直至外部活動的促發,然后流程才繼續. 這種的節點需要實現ExternalActivityBehaviour的API.

    														public interface ExternalActivityBehaviour extends ActivityBehaviour { 
    //handles an external trigger.
    void signal(ActivityExecution execution, String signalName, Map<String, ?> parameters) throws Exception;
    }

    跟內部節點類似,執行到ExternalActivityBehaviour的時候,也是執行它的execute()方法,但是一般來說,在外部活動的execute()方法中, 會調用execution.waitForSignal()方法,使得activity進入一個等待狀態. 直到外部調用signal()方法來使得流程再次從等待狀態變成激活.一般來說在signal()方法中,會調用execution.take(signalName)根據signalName(也就是transition name)去找到 下一個節點,然后把整個流程走到下一個節點.

    很簡單的一個例子是,比如說一個申請審批的流程,員工遞交一份申請上去,然后繼續就進入一個wait state的狀態,因為他需要經理的審批(也就是一個人工的活動),那么經理可以選擇一個ok的signalName,使得整個 流程進入到下一個節點,這里就好比如是結束的節點,又或者使得整個流程直接結束.

    我們接下來實現一個簡單的WaitState,實現ExternalActivityBehaviour的接口.

    														public class WaitState implements ExternalActivityBehaviour {

    public void execute(ActivityExecution execution) {
    execution.waitForSignal();
    }

    public void signal(ActivityExecution execution,
    String signalName,
    Map<String, Object> parameters) {
    execution.take(signalName);
    }
    }

    一樣的,我們來看一個簡單的從a->b的流程.這次不同的是,a和b都是wait state.


    ProcessDefinition的定義

    														ClientProcessDefinition pd = ProcessDefinitionBuilder.startProcess("helloworld")
    .startActivity("a", new WaitState())
    .initial()
    .transition("b", "b-transition")
    .endActivity()
    .startActivity("b", new WaitState())
    .endActivity()
    .endProcess();

    啟動這個ProcessDefinition

    														ClientProcessInstance instance = pd.startProcessInstance();
    instance.isActive("a")

    在啟動之后,因為執行到a的時候,是一個wait state,所以,當前的流程活動應該是指向a. 如果要到b這個activity,那么就需要調用

    														instance.signal("b-transition");
    instance.isActive("b")

    那么,你就會發現,經過我們調用signal方法,instance根據所提供的transitionName (b-transition),找到下一個節點,也就是b. 但因為b也是一個wait state,所以此刻,整個流程就停留在了b節點身上.

    接下來,我們基于前面兩種節點的實現,來實現一個稍微比較正式的流程(loan process).


    ProcessDefinition的定義

    															ClientProcessDefinition pd = ProcessDefinitionBuilder.startProcess("loanprocess")
    .startActivity("submit loan request", new Display("submit a loan request"))
    .initial()
    .transition("evaluate", "evaluate-transition")
    .endActivity()
    .startActivity("evaluate", new WaitState())
    .transition("wiremoney", "approve")
    .transition("end", "reject")
    .endActivity()
    .startActivity("wiremoney", new Display("wire the money"))
    .transition("archive")
    .endActivity()
    .startActivity("archive", new WaitState())
    .transition("end", "done")
    .endActivity()
    .startActivity("end", new WaitState())
    .endActivity()
    .endProcess();

    啟動這個processInstance

    														instance = pd.startProcessInstance();

    啟動這個processInstance后,它開始點在submit loan request這個節點,后面經過Display這個節點,默認走到了evaluate這個節點. 因為evaluate是個wait state,所以流程停在了evaluate.


    現在呢, evaluate這個節點有兩條支路,一個是approve,指向wiremoney節點;另外一個是reject,直接走向end. 假設我們選擇approve這條支路.

    														instance.signal("approve");

    那么,我們就走向了wiremoney這個節點,因為wiremoney是個Display節點,所以它顯示完后,默認的走向下一個節點,archive.


    同樣的,因為archive節點是個wait state,所以需要再一次的signal,才能走到end這個節點.

    														instance.signal("done");

    這樣的話,整個流程就會走向了end節點.


    事件的訂閱可以通過實現EventListener來實現.

    														public interface EventListener extends Serializable {
    void notify(EventListenerExecution execution) throws Exception;
    }

    Event概念的引入,主要是為了彌補分析員(Business Analyst)和開發人員(Developer)之間的不同需求. developer可以使用Event在一些節點上來做一些操作(比如說操作數據庫),這樣呢,也不會影響整個流程,所以分析員不用去關心這些具體的Event, 他們只需要看流程是否跟他們所期望的是一致的.

    具體的Event是由ObservableElementEventName來構成的.

    														public interface EventListenerExecution extends OpenExecution {
    void fire(String eventName, ObservableElement eventSource);
    }

    我們來實現一個簡單的EventListener, 叫PrintLn

    														public class PrintLn implements EventListener {

    String message;

    public PrintLn(String message) {
    this.message = message;
    }

    public void notify(EventListenerExecution execution) throws Exception {
    System.out.println(message);
    }
    }


    我們看下是怎么來定義一個具備有Events的ProcessDefinition:

    														ClientProcessDefinition pd = ProcessDefinitionBuilder.startProcess("ab")
    .startActivity("a", new Display("Testing Event"))
    .initial()
    .transition("b")
    .startEvent(Event.END)
    .listener(new PrintLn("leaving a"))
    .listener(new PrintLn("second message while leaving a"))
    .endEvent()
    .startEvent(Event.TAKE)
    .listener(new PrintLn("taking transition"))
    .endEvent()
    .endActivity()
    .startActivity("b", new WaitState())
    .startEvent(Event.START)
    .listener(new PrintLn("entering b"))
    .endEvent()
    .endActivity()
    .endProcess();

    我們可以看到,一個事件可以有無窮多個的Listener(s).

    至此,我們主要看了PVM里面內部Model的一些設計,一些核心的概念和API.

    posted on 2009-07-14 13:15 禮物 閱讀(1339) 評論(0)  編輯  收藏 所屬分類: JBPM4
    主站蜘蛛池模板: 成人黄动漫画免费网站视频 | 在线观看人成视频免费无遮挡| 国产亚洲综合色就色| 在线观看免费高清视频| 一区在线免费观看| 456亚洲人成在线播放网站| 国产精品亚洲综合专区片高清久久久| 在线免费观看国产| 两性色午夜免费视频| 亚洲第一第二第三第四第五第六| 无码乱人伦一区二区亚洲一| 免费在线观看理论片| 最近免费中文字幕大全视频| 9420免费高清在线视频| 国产成人精品无码免费看| 久久久久久噜噜精品免费直播| 在线观看亚洲视频| 男人的天堂av亚洲一区2区| 亚洲综合无码一区二区痴汉| 中文文字幕文字幕亚洲色| 亚洲天天做日日做天天欢毛片| 国产亚洲精品激情都市| 国产亚洲精品影视在线产品 | 欧亚一级毛片免费看| 免费福利资源站在线视频| 亚洲av日韩精品久久久久久a| 亚洲av无码专区亚洲av不卡| 亚洲国产成人无码AV在线| 午夜在线免费视频| 国产免费阿v精品视频网址| 嫩草成人永久免费观看| 性色午夜视频免费男人的天堂| 国产成人AV片无码免费| 十八禁无码免费网站| 18以下岁毛片在免费播放| 成年网站免费视频A在线双飞| 午夜国产精品免费观看| 国产精品久免费的黄网站| 亚洲欧洲国产成人综合在线观看| 亚洲无码高清在线观看| 亚洲春黄在线观看|