嚮應用程式中加入jBPM元件

weixin_34262482發表於2006-10-23
 
本文介紹怎樣把jBPM元件新增到Web應用程式中。所需要用到的資源,可以在jbpm-starters-kit-3.1.2中找到。
一、首先安裝jBPM資料庫。jBPM是一個停止狀態的元件,需要資料庫表持久化儲存:1)業務程式定義和業務程式例項及相關的工作流資料。保障工作流引擎的執行。2)非同步系統使用資料庫表來模擬訊息系統的功能。需要把訊息到資料庫表中,由訊息系統的命令執行器非同步查詢和執行。不像專業的訊息系統那樣是遠端的。它僅僅使用資料庫模擬訊息系統。
1,開啟MySQL的命令執行工具Query Browser。
2,當前選定應用程式的資料庫,如wcms。
3,匯入指令碼檔案:mysql.drop.create.sql
4,執行該指令碼。會在當前資料庫中增加jBPM的資料庫表。
 
二、匯入jBPM所需的.jar檔案
1,jbpmlib目錄中包含了jBPM所需的全部jar包。包括MySQL的jdbc包。
2,把它整個複製到應用程式的lib目錄下。
3,應用程式的構建器路徑的“庫”中,把這些jar都加進來。
這些classpath下的jar包,都會被該Web應用程式的類載入器載入。
 
三、建立config.files和processes目錄,並加入classpath的原始碼路徑
(一)config.files目錄的功能
    這個目錄存放jBPM的各類配置檔案。放在這裡(就是classpath頂層)的配置檔案會取代jBPM的jar包中各處的配置檔案。
這裡,由於需要使用mysql,而不是內建的hsql記憶體資料庫。所以我們提供了一個修改過的配置檔案:hibernate.cfg.xml。這裡提供了Hibernate3的配置。
hibernate.cfg.xml配置檔案的部分內容
<hibernate-configuration>
  <session-factory>
    <!-- jdbc connection properties
原來的HSQL配置被註釋掉,使用MySQL資料庫的配置
  <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:.;sql.enforce_strict_size=true</property>
    <property name="hibernate.connection.username">sa</property>
    <property name="hibernate.connection.password"></property>
          -->
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/wcms</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root</property>
(二)processes目錄的功能
這個目錄存放process流程定義。如:manageNews/內有3個檔案。
在jBPM應用程式匯入.par或.xml檔案時,使用相對路徑(如:withubCMS/processdefinition.xml)來定位業務程式定義資原始檔。
 
怎樣把它們放到classpath下,需要根據不同的環境進行不同的處理。
一、一般Java程式
    1,建立config.files和processes目錄。
2,配置構建器路徑,將這2個目錄設為到classpath的原始碼路徑。
這樣,執行時,會把它們中的內容複製到classpath目錄下。
二、Eclipse下的Web程式
我們使用Eclipse自帶的功能釋出Web程式。
    1,建立config.files和processes目錄。
2,配置構建器路徑,將這2個目錄設為到classpath的原始碼路徑。
3,配置classpath,也就是“預設輸出資料夾”,為:
內容管理(應用程式根路徑名)/webapps/WEB-INF/classes
4,這樣,在Eclipse編譯時(預設是儲存即編譯),把這2個資料夾中的內容複製到classpath下。
5,然後,使用Eclipse自帶的功能,釋出該Web應用程式。
Eclipse會把/webapps/資料夾下的所有內容複製到Web伺服器下,並且把webapps改名為該Web應用程式的Eclipse專案名字。
這樣,我們的配置,對於classpath來說也是正確的!Web應用程式可以順利地執行。
三、Ant釋出的Web程式
可以和上面一樣。把這些classpath的原始檔,編譯,然後把內部的內容複製到classpath下。
Web專案執行時的classpath是classes和lib。當然也需要把jar包都複製到lib下。
 
最後,在內容管理/webapps/WEB-INF/jbpm/下放置那2個目錄。並把它們設為classpath的源路徑。
目標classpath路徑是內容管理/webapps/WEB-INF/classes。
 
 
四、測試jBPM和資料庫
建立test原始檔夾。提供一個junit測試類:org.jbpm.test.db.HelloWorldDbTest
這個類使用字串定義了一個簡單的業務程式,然後在資料庫上完整的執行它。
執行該單元測試。在應用程式的資料庫中的2個表:
SELECT * FROM jbpm_processdefinition j;
SELECT * FROM jbpm_processinstance j;
應該有資料。
 
    至此,jBPM元件就成功地加入到Web應用程式中了!
附錄:HelloWorldDbTest.java原始碼
package org.jbpm.test.db;
import java.util.List;
import junit.framework.TestCase;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.db.GraphSession;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
public class HelloWorldDbTest extends TestCase {
 
  static JbpmConfiguration jbpmConfiguration = null;
  static {
    // An example configuration file such as this can be found in
    // 'src/config.files'.  Typically the configuration information is in the
    // resource file 'jbpm.cfg.xml', but here we pass in the configuration
    // information as an XML string.
   
    // First we create a JbpmConfiguration statically.  One JbpmConfiguration
    // can be used for all threads in the system, that is why we can safely
    // make it static.
   /**
    *單例物件。
    *JbpmConfiguration能夠被系統中所有執行緒所使用。
    *jbpm.cfg.xml這個命名方式和Hibernate配置檔案的命名方式一致。
    *
    */
    jbpmConfiguration = JbpmConfiguration.parseXmlString(
      "<jbpm-configuration>" +
     
      // A jbpm-context mechanism separates the jbpm core
      // engine from the services that jbpm uses from
      // the environment.
      /*jbpm-context機制在環境中把jbpm核心引擎和jbpm使用的服務分開。
       * 持久化服務是jbpm核心引擎使用的一個服務。
       *
       * */
     
      "  <jbpm-context>" +
      "    <service name='persistence' " +
      "             factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" +
      "  </jbpm-context>" +
     
      // Also all the resource files that are used by jbpm are
      // referenced from the jbpm.cfg.xml
      /*
       *string,配置了所有jbpm使用的資原始檔的路徑。
       * */
     
      "  <string name='resource.hibernate.cfg.xml' " +
      "          value='hibernate.cfg.xml' />" +
      "  <string name='resource.business.calendar' " +
      "          value='org/jbpm/calendar/jbpm.business.calendar.properties' />" +
      "  <string name='resource.default.modules' " +
      "          value='org/jbpm/graph/def/jbpm.default.modules.properties' />" +
      "  <string name='resource.converter' " +
      "          value='org/jbpm/db/hibernate/jbpm.converter.properties' />" +
      "  <string name='resource.action.types' " +
      "          value='org/jbpm/graph/action/action.types.xml' />" +
      "  <string name='resource.node.types' " +
      "          value='org/jbpm/graph/node/node.types.xml' />" +
      "  <string name='resource.varmapping' " +
      "          value='org/jbpm/context/exe/jbpm.varmapping.xml' />" +
      "</jbpm-configuration>"
    );
  }
 
  public void setUp() {
   //建立資料庫表
    //jbpmConfiguration.createSchema();
  }
 
  public void tearDown() {
   //刪除資料庫表
    //jbpmConfiguration.dropSchema();
  }
  public void testSimplePersistence() {
    // Between the 3 method calls below, all data is passed via the
    // database.  Here, in this unit test, these 3 methods are executed
    // right after each other because we want to test a complete process
    // scenario情節.  But in reality, these methods represent different
    // requests to a server.
   
    // Since we start with a clean, empty in-memory database, we have to
    // deploy the process first.  In reality, this is done once by the
    // process developer.
   /**
    *  這個方法把業務處理定義通過Hibernate儲存到資料庫中。
    */
    deployProcessDefinition();
    // Suppose we want to start a process instance (=process execution)
    // when a user submits a form in a web application...
    /*假設當一個使用者提交一個表單時,我們要開始一個業務處理的例項/執行。
     * 這可以在Action中執行處理。
     */
    processInstanceIsCreatedWhenUserSubmitsWebappForm();
    // Then, later, upon the arrival of an asynchronous message the
    // execution must continue.
    /*
     * 然後,直到非同步訊息來到,才繼續執行業務處理例項的餘下的工作流程。
     * */
    theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
  }
  public void deployProcessDefinition() {
    // This test shows a process definition and one execution
    // of the process definition.  The process definition has
    // 3 nodes: an unnamed start-state, a state 's' and an
    // end-state named 'end'.
   /*
    * 這個方法把業務處理定義通過Hibernate儲存到資料庫中。
    *
    * */
    ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
      "<process-definition name='hello world'>" +
      "  <start-state name='start'>" +
      "    <transition to='s' />" +
      "  </start-state>" +
      "  <state name='s'>" +
      "    <transition to='end' />" +
      "  </state>" +
      "  <end-state name='end' />" +
      "</process-definition>"
    );
    // Lookup the pojo persistence context-builder that is configured above
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {
      // Deploy the process definition in the database
      jbpmContext.deployProcessDefinition(processDefinition);
    } finally {
      // Tear down the pojo persistence context.
      // This includes flush the SQL for inserting the process definition 
      // to the database.
     /*
      * 關閉jbpm上下文。刪除pojo持久化上下文。
      * 這包括重新整理SQL來真正的把業務處理定義插入到資料庫中。
      * */
      jbpmContext.close();
    }
  }
  public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {
    // The code in this method could be inside a struts-action
    // or a JSF managed bean.
    // Lookup the pojo persistence context-builder that is configured above
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {
/*
 * 圖表會話,是圖表定義/業務處理定義 相關的資料庫層面的會話。應該也是一個Hibernate會話。
 * 可以從JBpm上下文這個資料庫----業務處理定義、例項等 得到 業務處理定義會話。
 *
 * */
      GraphSession graphSession = jbpmContext.getGraphSession();
      //從資料庫中根據業務處理定義的名字得到一個業務處理定義。
      ProcessDefinition processDefinition =
          graphSession.findLatestProcessDefinition("hello world");
   
      // With the processDefinition that we retrieved from the database, we
      // can create an execution of the process definition just like in the
      // hello world example (which was without persistence).
      /*
       * 建立業務處理定義的一個例項。
       *
       * */
      ProcessInstance processInstance =
          new ProcessInstance(processDefinition);
     
      Token token = processInstance.getRootToken();
      assertEquals("start", token.getNode().getName());
      // Let's start the process execution
      token.signal();
      // Now the process is in the state 's'.
      assertEquals("s", token.getNode().getName());
     
      // Now the processInstance is saved in the database.  So the
      // current state of the execution of the process is stored in the
      // database.
      /*
       * 執行一步工作流程後,使用jbpmContext儲存這個業務處理例項進資料庫。
       *    所以現在就把業務處理例項的執行狀態也儲存進了資料庫。
       *  因為,業務處理定義的例項  這個類也是一個Model類,用於管理一個業務處理定義的執行的所有資訊,
       *  是一個多例模式的Model。
       *
       * */
      jbpmContext.save(processInstance);
      // The method below will get the process instance back out
      // of the database and resume execution by providing another
      // external signal.
    } finally {
      // Tear down the pojo persistence context.
      jbpmContext.close();
    }
  }
  public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {
    // The code in this method could be the content of a message driven bean.
    //這個方法可能在訊息驅動Bean這個遠端業務代理類中。
    // Lookup the pojo persistence context-builder that is configured above
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {
      GraphSession graphSession = jbpmContext.getGraphSession();
      // First, we need to get the process instance back out of the database.
      // There are several options to know what process instance we are dealing
      // with here.  The easiest in this simple test case is just to look for
      // the full list of process instances.  That should give us only one
      // result.  So let's look up the process definition.
     
      ProcessDefinition processDefinition =
          graphSession.findLatestProcessDefinition("hello world");
      // Now, we search for all process instances of this process definition.
      /*
       * 根據業務處理定義的id得到資料庫中所有的業務處理例項。這表明,資料庫中應該存在2張表
       * 它們是  一對多  的關係。
       *
       * */
      List processInstances =
          graphSession.findProcessInstances(processDefinition.getId());
     
      // Because we know that in the context of this unit test, there is
      // only one execution.  In real life, the processInstanceId can be
      // extracted from the content of the message that arrived or from
      // the user making a choice.
      ProcessInstance processInstance =
          (ProcessInstance) processInstances.get(0);
     
      // Now we can continue the execution.  Note that the processInstance
      // delegates signals to the main path of execution (=the root token).
      processInstance.signal();
      // After this signal, we know the process execution should have
      // arrived in the end-state.
      assertTrue(processInstance.hasEnded());
     
      // Now we can update the state of the execution in the database
      jbpmContext.save(processInstance);
    } finally {
      // Tear down the pojo persistence context.
      jbpmContext.close();
    }
  }
}
 

相關文章