JBoss jBPM(Workflow Management Engine)[摘]

源文來自: http://blog.matrix.org.cn/page/joeyta?entry=jboss_jbpm_workflow_management_engine

JBoss jBPM (JAVA Business Process Management) 為開源工作流程引擎,
具有非常高的彈性及可擴展性, 可使用圖形介面事先定義工作流程序述,
提供非同步, 排程, 自動觸發動作等功能,

JBoss jBPM 可以與任何的資料庫集成, 並能嵌入於任何的JAVA企業應用系統.

開始備忘記:
[1] 安裝 jdk 5
[2] 安裝 JBoss jBPM server
[3] 安裝 Eclipse WTP
[4] 安裝 JBoss IDE
[5] 建立第一個 jBPM project

[1] 安裝 jdk 5:
下載 jdk-1_5_0_07-nb-5_0-win-ml.exe
http://java.sun.com/j2se/1.5.0/download-netbeans.html
安裝至 D:/jdk1.5.0_07
新增環境變數 JAVA_HOME=D:/jdk1.5.0_07
D:/jdk1.5.0_07/bin 加入至 PATH 中
D:/jdk1.5.0_07/lib/dt.jar 及 D:/jdk1.5.0_07/lib/tools.jar 加入至 CLASSPATH 中
執行 D:/>java -version
輸出 java version "1.5.0_07" 即安裝成功.

[2] 安裝 JBoss jBPM server:
下載 jbpm-starters-kit-3.1.2.zip
http://www.jboss.com/products/jbpm/downloads
http://superb-west.dl.sourceforge.net/sourceforge/jbpm/jbpm-starters-kit-3.1.2.zip
解壓縮至 D:/jboss_jbpm
D:/jboss_jbpm/readme.html 介紹每個目錄的功能.
這裡只需要關心 D:/jboss_jbpm/jbpm-server 目錄, 這是 JBoss jBPM server
執行 D:/jboss_jbpm/jbpm-server/start.bat 啟動 JBoss jBPM server
JBoss jBPM server 已提供了一個 JSF 的 web sale order 的例子.
進入 http://localhost:8080/jbpm/
隨便選一個 user 登入, 就可以測試預設的 web sale order workflow.

如下圖所示


官方的介面使用教學:
http://wiki.jboss.org/wiki/Wiki.jsp?page=JbpmGettingStarted

[3] 安裝 Eclipse WTP:
下載 wtp-all-in-one-sdk-R-1.5.0-200606281455-win32.zip
http://www.eclipse.org/webtools/
http://www.eclipse.org/downloads/download.php?file=/webtools/downloads/drops/R-1.5.0-200606281455/wtp-all-in-one-sdk-R-1.5.0-200606281455-win32.zip
解壓至 D:/eclipse_wtp

[4] 安裝 JBoss IDE:
Eclipse:Help -> Software Updates -> Find and Install -> Search for new features to install
New Remote Site
Name: JBOSS IDE
URL: http://download.jboss.org/jbosside/updates/stable
選擇最新的版本然後安裝.

[5] 建立第一個 jBPM project:
Eclipse:
File -> New -> Other -> JBoss jBPM -> Process Project
Project Name: First_jBPM -> Next -> Finish
預設會產生一整套測試檔案, 這備忘記就是對這些檔案作簡介.
如果想更深入了解 jBPM , 查看官方的文檔是最好的方法.

檔案結構如下所示


右鍵點選 gpd.xml -> Open With -> Text Editor , 就會出現如下所示代碼
<!---------------------- gpd.xml --------------------->
<?xml version="1.0" encoding="UTF-8"?>

<process-diagram name="simple" width="469" height="438">
  <node name="start" x="150" y="25" width="140" height="40">
    <transition name="to_state"/>
  </node>
  <node name="first" x="150" y="125" width="140" height="40">
    <transition name="to_end"/>
  </node>
  <node name="end" x="150" y="225" width="140" height="40"/>
</process-diagram>
<!---------------------- gpd.xml --------------------->
這是 graphical process designer 的描述檔案.
這裡只是簡單描述三個 nodes 的位置: start , first, end

右鍵點選 processdefinition.xml -> Open With -> Text Editor , 就會出現如下所示代碼
<!---------------------- processdefinition.xml --------------------->
<?xml version="1.0" encoding="UTF-8"?>

<process-definition
  xmlns="urn:jbpm.org:jpdl-3.1"
  name="simple">
   <start-state name="start">
     <task>
        <controller>
          <variable name="color" />
          <variable name="size" />
        </controller>
      </task>
      <transition name="to_state" to="first">
         <action name="action" class="com.sample.action.MessageActionHandler">
            <message>Going to the first state!</message>
         </action>
      </transition>
   </start-state>
   <state name="first">
      <transition name="to_end" to="end">
         <action name="action" class="com.sample.action.MessageActionHandler">
            <message>About to finish!</message>
         </action>
      </transition>
   </state>
   <end-state name="end"></end-state>
</process-definition>
<!---------------------- processdefinition.xml --------------------->
workflow engine 將根據此流程檔運作.
<start-state name="start"> 流程初始點.

<transition name="to_state" to="first">
 <action name="action" class="com.sample.action.MessageActionHandler">
  <message>Going to the first state!</message>
 </action>
</transition>
這裡描述初始點將過渡至 first 點.
而過渡至 first 點時會觸發 com.sample.action.MessageActionHandler [後面會介紹]
並設定此 ActionHandler 的 message 為 "Going to the first state!"

<state name="first">
 <transition name="to_end" to="end">
  <action name="action" class="com.sample.action.MessageActionHandler">
   <message>About to finish!</message>
  </action>
 </transition>
</state>

這裡描述 first 點. 通過此點將過渡至 end 點.
而過渡至 end 點時會觸發 com.sample.action.MessageActionHandler [後面會介紹]
並設定此 ActionHandler 的 message 為 "About to finish!"

<end-state name="end"> 流程結速點.


右鍵點選 processdefinition.xml -> Open With -> jBPM Graphical Process Designer
然後點 Diagram , 就會出現如下圖所示


可以使用 GPD (Graphical Process Designer) 來繪製 workflow
為了簡化備忘記, 參考以下官方教學文檔
http://docs.jboss.com/jbpm/v3/gpd


/*------------------ MessageActionHandler.java -------------------*/
package com.sample.action;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
public class MessageActionHandler implements ActionHandler { 
 // 這是 Listener, 觸發這個 Action 將執行 execute method
 private static final long serialVersionUID = 1L;

 String message;

 public void execute(ExecutionContext context) throws Exception {
  context.getContextInstance().setVariable("message", message); 
  // 這裡將上面觸發的 message 加入到該點的 message property
 }

}
/*------------------ MessageActionHandler.java -------------------*/


/*------------------ SimpleProcessTest.java -------------------*/
package com.sample;
import java.io.FileInputStream;
import junit.framework.TestCase;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
public class SimpleProcessTest extends TestCase {

 public void testSimpleProcess() throws Exception {

  FileInputStream fis = new FileInputStream("processes/simple/processdefinition.xml");
  ProcessDefinition processDefinition = ProcessDefinition.parseXmlInputStream(fis);
  // 讀取 processdefinition.xml 的流程定義檔
    
  assertNotNull("Definition should not be null", processDefinition);
  // 測試這個檔案並不為 null

  ProcessInstance instance = new ProcessInstance(processDefinition);
  // 建立處理流程檔實例
  
  assertEquals(
    "Instance is in start state",
    instance.getRootToken().getNode().getName(),
    "start");
    // 測試現在正處於 start 點    
    
  assertNull(
    "Message variable should not exist yet",
    instance.getContextInstance().getVariable("message"));
    // 測試 start 點的 message 為 null    

  instance.signal();
  // 呼叫 signal() 表示此點處理完成, 將跳至下一點
  // 由於上面設定了 ActionHandler, 將會設定 message 為  "Going to the first state!"

  
  assertEquals(
    "Instance is in first state",
    instance.getRootToken().getNode().getName(),
    "first");
    // 測試現在正處於 first 點     
    
  assertEquals(
    "Message variable contains message",
    instance.getContextInstance().getVariable("message"),
    "Going to the first state!");
    // 由於已經觸發 MessageActionHandler,
    // 測試此點 message property 為 "Going to the first state!"

    
  instance.signal();
  // 呼叫 signal() 表示此點處理完成, 將跳至下一點
  // 由於上面設定了 ActionHandler, 將會設定 message 為 "About to finish!"

  
  assertEquals(
    "Instance is in end state",
    instance.getRootToken().getNode().getName(),
    "end");
    // 測試現在正處於 end 點
    
  assertTrue("Instance has ended", instance.hasEnded());
  // 測試現在是最後終點
  
  assertEquals(
    "Message variable is changed",
    instance.getContextInstance().getVariable("message"),
    "About to finish!");
    // 由於已經觸發 MessageActionHandler,
    // 測試此點 message property 為 "About to finish!"

 }
}
/*------------------ SimpleProcessTest.java -------------------*/

點選 SimpleProcessTest.java -> Run As -> JUnit Test
如下所示即測試成功


Console 輸出為:
00:33:44,597 [main] INFO  JbpmConfiguration : using jbpm configuration resource ’jbpm.cfg.xml’
00:33:44,644 [main] DEBUG JbpmConfiguration : loading defaults in jbpm configuration
00:33:45,269 [main] DEBUG ObjectFactoryImpl : adding object info ’default.jbpm.context’
00:33:45,269 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.hibernate.cfg.xml’
00:33:45,269 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.business.calendar’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.default.modules’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.converter’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.action.types’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.node.types’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.parsers’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’resource.varmapping’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’jbpm.msg.wait.timout’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’jbpm.byte.block.size’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’mail.smtp.host’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’jbpm.task.instance.factory’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’jbpm.variable.resolver’
00:33:45,285 [main] DEBUG ObjectFactoryImpl : adding object info ’jbpm.mail.address.resolver’
00:33:45,285 [main] DEBUG JbpmConfiguration : loading specific configuration...
00:33:45,753 [main] DEBUG JpdlParser$JpdlEntityResolver : resolving schema reference publicId(null) systemId(
http://jbpm.org/jpdl-3.1.xsd)
00:33:45,753 [main] DEBUG JpdlParser$JpdlEntityResolver : providing input source to local ’jpdl-3.1.xsd’ resource
00:33:46,019 [main] WARN  JpdlXmlReader : process xml warning: warning: no swimlane or assignment specified for task ’<task xmlns="urn:jbpm.org:jpdl-3.1" blocking="false" signalling="true" priority="normal">
        <controller config-type="field">
          <variable name="color" access="read,write"/>
          <variable name="size" access="read,write"/>
        </controller>
      </task>’
00:33:46,081 [main] DEBUG GraphElement : event ’process-start’ on ’ProcessDefinition(simple)’ for ’Token(/)’
00:33:46,081 [main] DEBUG GraphElement : event ’before-signal’ on ’StartState(start)’ for ’Token(/)’
00:33:46,081 [main] DEBUG GraphElement : event ’node-leave’ on ’StartState(start)’ for ’Token(/)’
00:33:46,081 [main] DEBUG GraphElement : event ’transition’ on ’Transition(to_state)’ for ’Token(/)’
00:33:46,081 [main] DEBUG GraphElement : executing action ’action[action]’
00:33:46,113 [main] DEBUG VariableContainer : create variable ’message’ in ’TokenVariableMapc4aad3’ with value ’Going to the first state!’
00:33:46,159 [main] DEBUG Converters : adding converter ’D’, ’org.jbpm.context.exe.converter.DoubleToStringConverter’
00:33:46,159 [main] DEBUG Converters : adding converter ’C’, ’org.jbpm.context.exe.converter.CharacterToStringConverter’
00:33:46,159 [main] DEBUG Converters : adding converter ’B’, ’org.jbpm.context.exe.converter.BooleanToStringConverter’
00:33:46,159 [main] DEBUG Converters : adding converter ’Y’, ’org.jbpm.context.exe.converter.BytesToByteArrayConverter’
00:33:46,159 [main] DEBUG Converters : adding converter ’A’, ’org.jbpm.context.exe.converter.DateToLongConverter’
00:33:46,159 [main] DEBUG Converters : adding converter ’R’, ’org.jbpm.context.exe.converter.SerializableToByteArrayConverter’
00:33:46,175 [main] DEBUG Converters : adding converter ’I’, ’org.jbpm.context.exe.converter.IntegerToLongConverter’
00:33:46,175 [main] DEBUG Converters : adding converter ’H’, ’org.jbpm.context.exe.converter.ShortToLongConverter’
00:33:46,175 [main] DEBUG Converters : adding converter ’G’, ’org.jbpm.context.exe.converter.FloatToDoubleConverter’
00:33:46,191 [main] DEBUG Converters : adding converter ’F’, ’org.jbpm.context.exe.converter.FloatToStringConverter’
00:33:46,191 [main] DEBUG Converters : adding converter ’E’, ’org.jbpm.context.exe.converter.ByteToLongConverter’
00:33:46,206 [main] DEBUG GraphElement : event ’node-enter’ on ’State(first)’ for ’Token(/)’
00:33:46,206 [main] DEBUG GraphElement : event ’after-signal’ on ’StartState(start)’ for ’Token(/)’
00:33:46,206 [main] DEBUG GraphElement : event ’before-signal’ on ’State(first)’ for ’Token(/)’
00:33:46,206 [main] DEBUG GraphElement : event ’node-leave’ on ’State(first)’ for ’Token(/)’
00:33:46,222 [main] DEBUG GraphElement : event ’transition’ on ’Transition(to_end)’ for ’Token(/)’
00:33:46,222 [main] DEBUG GraphElement : executing action ’action[action]’
00:33:46,222 [main] DEBUG VariableContainer : update variable ’message’ in ’TokenVariableMapc4aad3’ to value ’About to finish!’
00:33:46,222 [main] DEBUG GraphElement : event ’node-enter’ on ’EndState(end)’ for ’Token(/)’
00:33:46,222 [main] DEBUG GraphElement : event ’process-end’ on ’ProcessDefinition(simple)’ for ’Token(/)’
00:33:46,222 [main] DEBUG GraphElement : event ’after-signal’ on ’State(first)’ for ’Token(/)’

如下圖所示:


這裡只是簡單的介紹如何開發 workflow system,
並沒有實作用戶介面, 可集成至 JSP, JSF 或 Tapestry 實作.

如果需要 embed 到其他的系統, 可參考官方文檔:
http://docs.jboss.com/jbpm/v3/userguide/deployment.html

由於本人亦使用過 OpenWFE [Sourceforge workflow engine 熱門項目]
OpenWFE 功能比較強, 文檔亦很多, 也比較複雜.
但 JBoss jBPM 有 JBossIDE 支持, 感覺上比較容易開發.
總結是現在沒有一套 workflow engine 能滿足用戶的所有需求.

OpwnWFE 官方網頁:
http://www.openwfe.org,

JBoss jBPM 用戶手冊:
http://docs.jboss.com/jbpm/v3/userguide/

JBoss jBPM 官方文檔:
http://www.jboss.com/products/jbpm/docs

JBoss jBPM wiki:
http://wiki.jboss.org/wiki/Wiki.jsp?page=JbpmWiki

workflow pattern:
http://is.tm.tue.nl/research/patterns/

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值