渡邊です。こんにちは。
jBPM5の研究をしています。
備忘録を兼ねて、jBPM3系からjBPM5系への移行手順について概要を記します。
お題となりますのは、EJB3+jBPM3という構成のアプリケーションです。
このアプリケーションに組み込まれたjBPM3をjBPM5に移行する手順の概要を記します。
jBPM5のマイナーバージョンやAPサーバのバージョンによって、詳細な手順は変わるかもしれません。この投稿では細かいことは置いておきます。話を単純にする為、アプリケーション内のワークフロー定義は1つのみとします。全体的な手順は次の通りです。
- インターフェース抽出
- JAR入れ替え
- BPMN2ダイヤグラム作成
- META-INF
- 5系版セッションBean実装
- 組織テーブル作成
- サービス切り換え
それでは順に補足します。
インターフェース抽出
移行前のアプリケーションをリファクタリングします。既に次のようになっている場合は、不要な手順です。
jBPM3のパッケージが絡む処理を1つのセッションBeanに集約します。セッションBean内にjBPM3を隠ぺいするように、インターフェースを切り出します。
インターフェースは次のようになると思います。Modelは、プロセスに紐づけるエンティティとします。
@Local public interface ProcessService { /** * 初期化処理です。 */ void initialize(); /** * ワークフローを開始します。 */ void startProcess(Model model, String transition); /** * タスクを完了します。 */ void completeTask(Accounts actor, Model model, String transition); /** * 指定されたユーザにアサインされたタスクに関連付けられたModelのIDを返します。 */ ListfindModelIds(Accounts actor); }
JAR入れ替え
JARを入れ替えます。この記事を投稿するにあたり移行したアプリケーションにおいて、入れ替えたJARを示します(Droolsを入れ替えているだけで、jBPMについては5系を追加しているだけですね)。
- 追加したJAR
- drools-compiler-5.5.0.Final.jar
- drools-compiler.jar
- drools-core-5.5.0.Final.jar
- drools-decisiontables-5.5.0.Final.jar
- drools-persistence-jpa-5.5.0.Final.jar
- drools-pipeline-5.5.0.Final.jar
- drools-simulator-5.5.0.Final.jar
- drools-templates-5.5.0.Final.jar
- ecj-3.5.1.jar
- guvnor-repository-5.3.0.Final.jar
- guvnor-repository-connector-jackrabbit-5.3.0.Final.jar
- guvnor-repository-connector-jcr-5.3.0.Final.jar
- guvnor-repository-connector-modeshape-5.3.0.Final.jar
- jbpm-bam-5.4.0.Final.jar
- jbpm-bpmn2-5.4.0.Final.jar
- jbpm-flow-5.4.0.Final.jar
- jbpm-flow-builder-5.4.0.Final.jar
- jbpm-human-task-core-5.4.0.Final.jar
- jbpm-persistence-jpa-5.4.0.Final.jar
- jbpm-workitems-5.4.0.Final.jar
- knowledge-api-5.5.0.Final.jar
- knowledge-internal-api-5.5.0.Final.jar
- mvel2-2.1.3.Final.jar
- protobuf-java-2.4.1.jar
- stringtemplate-3.2.1.jar
- 削除したJAR
- drools-api.jar
- drools-compiler.jar
- drools-core.jar
- drools-decisiontables-5.0.1.jar
- drools-templates-5.0.1.jar
- mvel2.jar
BPMN2ダイヤグラム作成
BPMN2ダイヤグラムを作成し、オフラインで単体テストを済ませておきます。
jBPM5:BPMN2 Processの単体テスト
META-INF
JBossコミュニティからjbpm-persistence-jpa-5.x.x-sourcesをダウンロードし、同ファイルに同梱されたMETA-INFにある(MANIFEST.MF以外の)ファイルを、アプリケーションのMETA-INF直下にコピーします。
今回はjbpm-persistence-jpa-5.4.0.Final-sourcesを使いました。具体的には次のファイルをコピーしました。
- ExtraIndexes.hbm.xml
- JBPMorm.xml
- JBPMorm-JPA2.xml
- ProcessInstanceInfo.hbm.xml
- ProcessInstanceInfoMapping-JPA2.xml
persistence.xmlを編集します。ユーザガイドの「13.2.5. Starting the human task service」を参考にしました(バージョンによって目次番号が異なるかもしれません)。
具体的には、次の設定を追記しました。
<mapping-file>META-INF/JBPMorm-JPA2.xml</mapping-file> <mapping-file>META-INF/ProcessInstanceInfoMapping-JPA2.xml</mapping-file> <mapping-file>META-INF/Taskorm-JPA2.xml</mapping-file> <class>org.drools.persistence.info.SessionInfo</class> <class>org.drools.persistence.info.WorkItemInfo</class> <class>org.jbpm.process.audit.ProcessInstanceLog</class> <class>org.jbpm.process.audit.NodeInstanceLog</class> <class>org.jbpm.process.audit.VariableInstanceLog</class> <class>org.jbpm.task.Attachment</class> <class>org.jbpm.task.BooleanExpression</class> <class>org.jbpm.task.Comment</class> <class>org.jbpm.task.Content</class> <class>org.jbpm.task.Deadline</class> <class>org.jbpm.task.Delegation</class> <class>org.jbpm.task.EmailNotification</class> <class>org.jbpm.task.EmailNotificationHeader</class> <class>org.jbpm.task.Escalation</class> <class>org.jbpm.task.Group</class> <class>org.jbpm.task.I18NText</class> <class>org.jbpm.task.Notification</class> <class>org.jbpm.task.OnAllSubTasksEndParentEndStrategy</class> <class>org.jbpm.task.OnParentAbortAllSubTasksEndStrategy</class> <class>org.jbpm.task.PeopleAssignments</class> <class>org.jbpm.task.Reassignment</class> <class>org.jbpm.task.Status</class> <class>org.jbpm.task.SubTasksStrategy</class> <class>org.jbpm.task.Task</class> <class>org.jbpm.task.TaskData</class> <class>org.jbpm.task.User</class>
5系版セッションBean実装
最初の手順で抽出したインターフェースのjBPM5実装を作成します。JBoss World 2012 Keynoteで公開されているソースを参考にしました。
特にorg.jboss.jbw2012.keynote.process.ProcessControllerが参考になるのですが、一点、はまったことがあります。それについては、こちらに記しました。
ちょっと話は逸れますが、プロセスがあるタスクに達した時、そのプロセスに紐づくエンティティのステータスをそのタスクにあわせて自動更新したいという要件があるとします。そのような時は、次のようにProcessEventListenerを実装し、それをStatefulKnowledgeSession生成時に仕込みます(これは別記事に括りだした方がよさそうですね)。
private class UpdateCouponWorkflowStatusProcessEventListener extends DefaultProcessEventListener { @Override public void afterNodeTriggered(ProcessNodeTriggeredEvent event) { NodeInstance node = event.getNodeInstance(); if (node instanceof HumanTaskNodeInstance) { WorkItem workItem = ((HumanTaskNodeInstance)node).getWorkItem(); String id = (String)workItem.getParameter("id"); String status = (String)workItem.getParameter("workflowStatus"); updateWorkflowStatus(id, status); } if (node instanceof EndNodeInstance) { String id = (String)node.getVariable("id"); String status = node.getNodeName(); updatWorkflowStatus(id, status); } } private void updateWorkflowStatus(String id, String status) { ModelDao dao = ModelDao.getInstance(); Model model = dao.findById(id); model.setWorkflowStatus(status); dao.merge(coupon); } }
組織テーブル作成
jBPM5が作成するOrganizationalEntityテーブルに次のようにデータを登録します(この手順は、間違っているような気がします。正しい方法を模索中です)。
DTYPE | id |
---|---|
User | 1 |
User | 2 |
User | … |
User | N |
Group | Role1 |
Group | Role2 |
Group | … |
Group | RoleM |
カラムDTYPEの値”User”と”Group”は、固定値です。
カラムDTYPEの値が”User”となるレコードについては、ワークフローを利用する全ユーザ分登録します。カラムidには、各ユーザの識別子を設定します。
カラムDTYPEの値が”Group”となるレコードについては、アプリケーションで定義するグループ(役割)分登録します。カラムidには、各グループ(役割)の識別子を設定します。
ユーザ登録機能がある場合は、ユーザ登録時にOrganizationalEntityテーブルのレコードも作成するように改修します。
サービス切り換え
3系によるProcessServiceの実装をJBPM3ProcessService、5系によるものをJBPM5ProcessServiceとします。それぞれのセッションBeanに名前をつけていると思いますが、その名前を入れ替えます。
今回はフレームワークとしてSeamを使っていましたので、@Nameアノテーションの設定を次のように変更しました。
@Name("processService") public class JBPM3ProcessService implements ProcessService {
@Name("notInService") public class JBPM3ProcessService implements ProcessService { @Name("processService") public class JBPM5ProcessService implements ProcessService {
以上です。