程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> jBPM-4.0中文開發指南-第13章 執行模式

jBPM-4.0中文開發指南-第13章 執行模式

編輯:關於JAVA

第 13 章 執行模式

這裡有三種基本的流程執行模式:對象,持久化和嵌入。 對於持久化和嵌入執行模式, 流程執行必 須在一個事務中執行。在那種情況, 流程執行必須放在一個環境的內部。 環境將用來綁定流程執行,更 新到一個應用事務的事務中。 環境可以被用來綁定,比如一個JDBC連接, JTA,BMT,Spring事務等等。

13.1. 對象執行模式

對象執行模式是使用流程虛擬機的最簡單形式。 這意味著通過客戶端API直接使用流程定義和執行對 象。 讓我們通過一個例子演示這個。 我們通過創建一個ClientProcessDefinition開始,看起來像這樣 :

對象執行模式是使用流程虛擬機的最簡單形式。 這意味著通過客戶端API直接使用流程定義和執行對 象。 讓我們通過一個例子演示這個。 我們通過創建一個ClientProcessDefinition開始,看起來像這樣 :

圖 13.1. 貸款流程

ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
  .activity("submit loan request").initial().behaviour(AutomaticActivity.class)
    .transition().to("evaluate")
  .activity("evaluate").behaviour(WaitState.class)
     .transition("approve").to("wire money")
    .transition("reject").to("end")
  .activity("wire money").behaviour(AutomaticActivity.class)
    .transition().to ("archive")
  .activity("archive").behaviour(WaitState.class)
    .transition ().to("end")
  .activity("end").behaviour(WaitState.class)
.done();

ProcessFactory是一個幫助類, 為構建一個表現為流程定義的對象圖提供方便。 AutomaticActivity 是一個通過活動, 沒有任何操作發生,WaitState會等到外部signal發生。 這兩個活動實現都會在後面 討論更深。

processDefinition對象作為一個工廠,為流程實例對象。 一個流程實例表現為流程定義的一個執行 。 更准確的說,流程實例是執行的主路徑。

ClientExecution execution = processDefinition.startProcessInstance();

一個流程實例自己也是一個Execution. 潛在的,一個執行可以擁有子執行 表現執行的同步路徑。

execution可以看做是一個狀態機, 在流程定義裡像描述一樣操作。啟動一個流程實例意思是 流程定 義的初始節點被執行。 因為這是一個自動活動,執行會執行到evaluate活動。 evaluate活動是一個等待 狀態。 當執行到達evaluate活動,startProcessInstance方法 會返回並等待一個外部signal使用signal 方法提供。 所以在startProcessInstance之後,我們可以證實 如果執行定位在evaluate活動。

assertEquals("evaluate", execution.getActivityName());

為了讓流程執行得更遠,我們提供一個外部觸發器使用 signal方法。執行的結果會被作為 signalName參數給與,像這樣:

execution.signal("approve");

WaitState活動實現會根據給出的signalName 選擇轉移。所以執行將首先執行自動活動wire money 然 後在進入等待狀態archive後 返回。

assertEquals("archive", execution.getActivityName());

當執行在archive活動等待時,默認的signal會讓它 選擇第一個未命名的轉移。

execution.signal();
assertEquals("end", execution.getActivityName());

流程執行在客戶端的線程中。 startProcessInstance方法只在到達evaluate活動時返回。 換句話說 ,ClientProcessDefinition.startProcessInstance和 ClientExecution.signal方法會一直堵塞直到 下 一個等待狀態的到來。

13.2. 持久化執行模式

流程虛擬機也包含hibernate映射來保存流程定義和執行 在任何數據庫中。一個特定的會話外觀叫做 ExecutionService 被提供給流程執行 在這樣一個持久化環境中。

兩個配置文件應該放在classpath下:一個環境配置文件 和一個hibernate.properties文件。 一個持 久化執行模式的基礎配置,在一個標准Java環境 看起來像這樣:

environment.cfg.xml:

<jbpm-configuration>

  <process-engine-context>

    <deployer-manager>
      <assign-file-type>
        <file extension=".jpdl.xml" type="jpdl" />
      </assign-file-type>
       <parse-jpdl />
      <check-process />
      <check- problems />
      <save />
    </deployer-manager>

     <process-service />
    <execution-service />
    <management -service />

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

    <hibernate-configuration>
      <properties resource="hibernate.properties" />
      <mapping resource="jbpm.pvm.typedefs.hbm.xml" />
      <mapping resource="jbpm.pvm.wire.hbm.xml" />
      <mapping resource="jbpm.pvm.definition.hbm.xml" />
      <mapping resource="jbpm.pvm.execution.hbm.xml" />
      <mapping resource="jbpm.pvm.variable.hbm.xml" />
      <mapping resource="jbpm.pvm.job.hbm.xml" />
      <mapping resource="jbpm.jpdl.hbm.xml" />
      <cache-configuration resource="jbpm.pvm.cache.xml"
                            usage="nonstrict-read-write" />
    </hibernate-configuration>

    <hibernate-session-factory />

     <id-generator />
    <types resource="jbpm.pvm.types.xml" />
     <job-executor auto-start="false" />

  </process-engine- context>

  <transaction-context>
    <hibernate-session />
    <transaction />
    <pvm-db-session />
    <job-db-session />
    <message-session />
  </transaction- context>

</jbpm-configuration>

下一個,hibernate.properties像這樣:

hibernate.properties:

hibernate.dialect                      org.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class      org.hsqldb.jdbcDriver
hibernate.connection.url               jdbc:hsqldb:mem:.
hibernate.connection.username          sa
hibernate.connection.password
hibernate.hbm2ddl.auto                  create-drop
hibernate.cache.use_second_level_cache true
hibernate.cache.provider_class         org.hibernate.cache.HashtableCacheProvider
# hibernate.show_sql                      true
hibernate.format_sql                   true
hibernate.use_sql_comments             true

然後你可以從環境工廠中像這樣獲得服務:

EnvironmentFactory environmentFactory = new PvmEnvironmentFactory ("environment.cfg.xml");

ProcessService processService = environmentFactory.get (ProcessService.class);
ExecutionService executionService = environmentFactory.get (ExecutionService.class);
ManagementService managementService = environmentFactory.get (ManagementService.class);

ProcessService的責任是管理流程定義資源。 在我們可以啟動一個流程執行之前, 流程定義需要被 發布到流程資源庫中。 流程定義可以使用不同的格式和不同的流程語言提供。 一個發布包含了流程定義 信息,從不同的源文件中,像一個ZIP文件, 一個XML文件或一個流程定義對象。 ProcessService.deploy方法會獲得一個發布 通過配置在配置文件裡的所有發布器。

在這個例子中,我們通過代碼方式為發布 提供一個流程定義。

ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
  .activity("submit loan request").initial().behaviour(AutomaticActivity.class)
    .transition().to("evaluate")
  .activity("evaluate").behaviour(WaitState.class)
     .transition("approve").to("wire money")
    .transition("reject").to("end")
  .activity("wire money").behaviour(AutomaticActivity.class)
    .transition().to ("archive")
  .activity("archive").behaviour(WaitState.class)
    .transition ().to("end")
  .activity("end").behaviour(WaitState.class)
.done();

Deployment deployment = new Deployment(processDefinition);
processService.deploy(deployment);

現在流程定義的一個版本保存到數據庫中。 check-version發布器會把版本1 分配給存儲的流程定義 。create-id發布器 會提取idloan:1 根據流程名稱和分配的版本。

再次發布流程會導致在數據庫中創建一個新流程定義。 但是一個增加的版本數會被分配。 出於版本 化的目的,如果有相同的名字, 流程定義就會相同。

推薦用戶為所有流程執行提供key的引用。 啟動一個新流程執行像這樣:

Execution execution = executionService.startExecution("loan:1", "request7836");

返回值是一個execution接口,防止關系的向導。 那是因為服務方法外面,事務和hibernate會話沒有 保證一直打開。 實際上,上面給出的默認的配置只保證 事務和會話在服務方法執行中是打開的。 所以 服務方法外的關系導航可能引起一個hibernate的 LazyInitializationException. 但是當前的活動名稱 還可以被驗證。

assertEquals("evaluate", execution.getActivityName());

生成可以被獲得的id也是非常重要的。 默認的id-generator會用來生成流程定義的id 給出的key來為 流程執行生成一個唯一id,像這樣:

assertEquals("loan:1/request7836", execution.getId());

那個id必須提供給外部觸發器 像這樣處理流程執行:

executionService.signalExecution("loan:1/request7836", "approve");

關於服務接口的更多信息,關於如何運行在持久化模式下, 可以在包 org.jbpm.pvm 的api doc找到 。

13.3. 嵌入執行模式

嵌入執行模式意味著路程的狀態保存在 一個用戶領域對象的字符串列中,比如一個loan.

public class Loan {

  /** the loan process definition as a static resource */
  private static final ClientProcessDefinition processDefinition = createLoanProcess ();

  private static ClientProcessDefinition createLoanProcess() {
    ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
      .activity("submit loan request").initial().behaviour(AutomaticActivity.class)
         .transition().to("evaluate")
      .activity("evaluate").behaviour (WaitState.class)
        .transition("approve").to("wire money")
         .transition("reject").to("end")
      .activity("wire money").behaviour (AutomaticActivity.class)
        .transition().to("archive")
      .activity("archive").behaviour(WaitState.class)
        .transition().to("end")
      .activity("end").behaviour(WaitState.class)
    .done();

    return processDefinition;
  }

  /** exposes the process definition to the execution hibernate type */
  private static ClientProcessDefinition getProcessDefinition() {
    return processDefinition;
  }


  long dbid;
  String customer;
  double amount;
  ClientExecution execution;

  /** constructor for persistence */
  protected Loan() {
  }

  public Loan (String customer, double amount) {
    this.customer = customer;
    this.amount = amount;
    this.execution = processDefinition.startProcessInstance();
  }

  public void approve() {
    execution.signal("approve");
  }

  public void reject() {
    execution.signal("reject");
  }

  public void archiveComplete() {
    execution.signal();
  }

  public String getState() {
    return execution.getActivityName();
  }

  ...getters...
}

如果你暫時忽略加粗部分,你可以看到這是一個沒有任何奇異的POJO. 它只是一個bean,可以保存到 hibernate中。 粗體部分展示了類的實現部分,這與流程和執行相關。 流程定義或者執行都沒有暴露給 Loan類的用戶。

每個Loan對象對應一個loan流程實例。 Loan類的一些方法 對應外部觸發器, 這會在Loan對象的生命 周期被觸發。

接下來我們演示如何使用這個類,為了開始,我們需要一個

hibernate.cfg.xml:

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate- configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration- 3.0.dtd">

<hibernate-configuration>
  <session-factory>

     <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
    <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="hibernate.connection.url">jdbc:hsqldb:mem:.</property>
    <property name="hibernate.connection.username">sa</property>
    <property name="hibernate.connection.password"></property>
    <property name="hibernate.hbm2ddl.auto">create</property>
    <property name="hibernate.show_sql">true"</property>
    <property name="hibernate.format_sql">true"</property>
    <property name="hibernate.use_sql_comments">true"</property>

    <mapping resource="Loan.hbm.xml"/>

  </session-factory>
</hibernate- configuration>

和一個

Loan.hbm.xml:

<?xml version="1.0"?<

<!DOCTYPE hibernate-mapping PUBLIC
           "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"<

<hibernate- mapping package="org.jbpm.pvm.api.db.embedded" default-access="field"<

  <typedef name="execution" class="org.jbpm.pvm.internal.hibernate.ExecutionType" />

  <class name="Loan" table="LOAN"<

    <id name="dbid"<
      <generator class="sequence"/>
    </id<

    <property name="execution" type="execution" />
    <property name="customer" />
    <property name="amount" />

  </class<

</hibernate-mapping<

然後你可以在測試中像這樣使用Loan類

Configuration configuration = new Configuration();
configuration.configure ();
SessionFactory sessionFactory = configuration.buildSessionFactory();

// start a session/transaction
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

Loan loan = new Loan("john doe", 234.0);
session.save(loan);
assertEquals("evaluate", loan.getState());

// start a new session/transaction
transaction.commit();
session.close();
session = sessionFactory.openSession();
transaction = session.beginTransaction();

loan = (Loan) session.get(Loan.class, loan.getDbid());
assertEquals("evaluate", loan.getState ());
loan.approve();
assertEquals("archive", loan.getState());

// start a new session/transaction
transaction.commit();
session.close();

在執行這段代碼之後,這是在數據庫中的loan記錄:

圖 13.2. 數據庫中的貸款記錄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved