第4章 永続性
この章では、Business Process Manager の "永続性" 機能について詳しく説明します。
ほとんどの場合、jBPM は複数のトランザクションにまたがるプロセスを実行するために使用されます。永続性 機能の主な目的は、待機状態 が発生したときにプロセスの実行を保存することです。プロセスの実行は、ステートマシン として考えると理解しやすくなります。その目的は、プロセス実行ステートマシンを、1 つのトランザクションの中で、ある状態から次の状態に移動させることです。
プロセス定義は、XML、Java オブジェクト、または jBPM データベースレコードの 3 つの異なる形式のいずれかで表すことができます。(また、ランタイムデータとログ情報は、Java オブジェクトまたは jBPM データベースレコードの形式で表すことができます。)
図4.1 変換とさまざまな形式
注記
プロセス定義とプロセスアーカイブの XML 表現の詳細は、14章 jBPM プロセス定義言語 を参照してください。
注記
プロセスアーカイブをデータベースにデプロイする方法の詳細は、「 プロセスアーカイブのデプロイ 」 を参照してください。
4.1. 永続性アプリケーションプログラミングインターフェイス リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
4.1.1. 設定フレームワークとの関係 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
永続性アプリケーションプログラミングインターフェイスは、設定フレームワークと統合されています (3章 設定 を参照)。 これは、
JbpmContext の convenience persistence メソッドの一部を公開し、jBPM の コンテキストブロック が永続性 API 操作を呼び出せるようにすることで実現されています。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
// Invoke persistence operations here
} finally {
jbpmContext.close();
}
4.1.2. JbpmContext の便利なメソッド リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
最も一般的に実行される 3 つの永続性操作は次のとおりです。
- プロセスデプロイメント
- 新しいプロセスの実行開始
- プロセスの実行継続
プロセスデプロイメント は通常、Graphical Process Designer または
deployprocess ant タスクから直接実行されます。ただし、Java から直接実行するには、次のコードを使用します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition processDefinition = ...;
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
jbpmContext.close();
}
新しいプロセス実行のインスタンス化の対象になるプロセス定義を指定して、新しいプロセス実行を作成します。これを行う最も一般的な方法は、プロセスの名前を参照することです。すると、jBPM はデータベース内でそのプロセスの最新バージョンを検索します。以下にデモコードを示します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
String processName = ...;
ProcessInstance processInstance =
jbpmContext.newProcessInstance(processName);
} finally {
jbpmContext.close();
}
プロセスの実行を続行するには、データベースからプロセスインスタンス、トークン、または
taskInstance を取得し、POJO (Plain Old Java Object) jBPM オブジェクトでいくつかのメソッドを呼び出します。さrない、processInstance に加えられた更新をデータベースに保存します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
long processInstanceId = ...;
ProcessInstance processInstance =
jbpmContext.loadProcessInstance(processInstanceId);
processInstance.signal();
jbpmContext.save(processInstance);
} finally {
jbpmContext.close();
}
ForUpdate メソッドを JbpmContext クラスで使用する場合、jbpmContext.save メソッドを明示的に呼び出す必要はないことに注意してください。これは、jbpmContext クラスが閉じられると、保存プロセスが自動的に実行されるためです。たとえば、taskInstance が完了したことを jBPM に通知したい場合があります。これにより実行の継続が引き起こされることがあるため、taskInstance に関連する processInstance を保存する必要があります。これを行う最も便利な方法は、loadTaskInstanceForUpdate メソッドを使用することです。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
long taskInstanceId = ...;
TaskInstance taskInstance =
jbpmContext.loadTaskInstanceForUpdate(taskInstanceId);
taskInstance.end();
}
finally {
jbpmContext.close();
}
重要
以下の説明を読み、jBPM による永続性機能の管理方法と Hibernate の機能の使用方法を確認してください。
JbpmConfiguration は、一連の ServiceFactories を維持します。これらは jbpm.cfg.xml ファイルを介して設定され、必要に応じてインスタンス化されます。
DbPersistenceServiceFactory は、最初に必要になったときにのみインスタンス化されます。その後、ServiceFactory は JbpmConfiguration で維持されます。
DbPersistenceServiceFactory は Hibernate ServiceFactory を管理しますが、これは最初に要求されたときにのみインスタンス化されます。
DbPersistenceServiceFactory パラメーター:
isTransactionEnabledsessionFactoryJndiNamedataSourceJndiNameisCurrentSessionEnabled
図4.2 永続性関連のクラス
jbpmConfiguration.createJbpmContext () クラスが呼び出されると、JbpmContext のみが作成されます。この時点では、それ以上の永続性関連の初期化は行われません。JbpmContext は、DbPersistenceService クラスを管理します。このクラスは、最初に要求されたときにインスタンス化されます。DbPersistenceService クラスは、Hibernate セッションを管理します。これも、最初に必要になったときにのみインスタンス化されます。(つまり、Hibernate セッションは、永続性を必要とする最初の操作が呼び出されたときにのみ開かれます。)
4.2. 永続性サービスの設定 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
4.2.1. DbPersistenceServiceFactory リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
DbPersistenceServiceFactory クラスには、さらに isTransactionEnabled、sessionFactoryJndiName、および dataSourceJndiName という 3 つの設定プロパティーがあります。jbpm.cfg.xml ファイルでこれらのプロパティーを指定するには、factory 要素内で Bean として Service Factory を指定します。このサンプルコードは、その方法を示しています。
<jbpm-context>
<service name="persistence">
<factory>
<bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
<field name="isTransactionEnabled"><false /></field>
<field name="sessionFactoryJndiName">
<string value="java:/myHibSessFactJndiName" />
</field>
<field name="dataSourceJndiName">
<string value="java:/myDataSourceJndiName" />
</field>
</bean>
</factory>
</service>
...
</jbpm-context>
重要
ファクトリーを設定する際に、短い表記と長い表記を混在させないでください。(「 ファクトリーのカスタマイズ 」 も併せて参照してください。) ファクトリーがクラスの単なる新しいインスタンスである場合は、ファクトリー属性を使用してそのファクトリークラス名を参照します。一方、ファクトリーのプロパティーに設定が必要な場合は、長い表記を使用する必要があり、ファクトリーと Bean をネストされた要素として組み合わせる必要があります。
isTransactionEnabled- デフォルトでは、jBPM はセッションが初めて取得されたときに Hibernate トランザクションを開始します。
jbpmContextが閉じられると、Hibernate トランザクションは終了します。その後、jbpmContext.setRollbackOnlyが呼び出されたかどうかに応じて、トランザクションはコミットまたはロールバックされます。(isRollbackOnly プロパティーはTxServiceで維持されます。) トランザクションを無効にし、jBPM が Hibernate でそれらを管理するのを禁止するには、isTransactionEnabled プロパティー値をfalseに設定します。(このプロパティーはjbpmContextの動作のみを制御します。DbPersistenceService.beginTransaction()は、isTransactionEnabled 設定を無視するアプリケーションプログラミングインターフェイスを使用して直接呼び出すことができます。) トランザクションの詳細は、「 Hibernate トランザクション 」 を参照してください。 sessionFactoryJndiName- デフォルトでは、これは
nullです。これは、セッションファクトリーが JNDI から取得されないことを意味します。このプロパティーが設定されていて、Hibernate セッションを作成するためにセッションファクトリーが必要な場合は、JNDI から取得されます。 dataSourceJndiName- デフォルトでは、これは
nullです。その結果、JDBC 接続が作成され、Hibernate に委譲されます。データソースを指定すると、Business Process Manager は新しいセッションを開くとともに、データソースから JDBC 接続を取得し、それを Hibernate に提供します。
4.2.1.1. Hibernate セッションファクトリー リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
デフォルトでは、
DbPersistenceServiceFactory はクラスパスのルートにある hibernate.cfg.xml ファイルを使用して、Hibernate セッションファクトリーを作成します。Hibernate 設定ファイルのリソースが jbpm.hibernate.cfg.xml にマップされていることに注意してください。これは、jbpm.cfg.xml を再設定してカスタマイズします。
<jbpm-configuration>
<!-- configuration resource files pointing to default
configuration files in jbpm-{version}.jar -->
<string name='resource.hibernate.cfg.xml'
value='hibernate.cfg.xml' />
<!-- <string name='resource.hibernate.properties'
value='hibernate.properties' /> -->
</jbpm-configuration>
重要
resource.hibernate.properties が指定されている場合、そのリソースファイルのプロパティーは、
hibernate.cfg.xml のすべてのプロパティーを上書きします。データベースを参照するように hibernate.cfg.xml を更新するのではなく、hibernate.properties を使用して jBPM のアップグレードを処理してください。そうすることで、変更を再適用することなく hibernate.cfg.xml ファイルをコピーできます。
4.2.1.2. C3PO 接続プールの設定 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
http://www.hibernate.org/214.html で Hibernate のドキュメントを参照してください。
4.2.1.3. ehCache プロバイダーの設定 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
JBossCache を使用して jBPM を設定する方法については、http://wiki.jboss.org/wiki/Wiki.jsp?page=JbpmConfiguration を参照してください。
Hibernate と連携するようにキャッシュプロバイダーを設定する方法については、http://www.hibernate.org/hib_docs/reference/en/html/performance.html#performance-cache を参照してください。
jBPM に付属する
hibernate.cfg.xml ファイルには、次の行が含まれています。
<property name="hibernate.cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</property>
これは、ユーザーがクラスパスの設定を気にする必要がないように提供されています。
警告
Hibernate の
HashtableCacheProvider を実稼働環境で使用しないでください。
HashtableCacheProvider の代わりに ehcache を使用するには、関連する行をクラスパスから削除し、代わりに ehcache.jar を使用します。お使いの環境と互換性のある正しい ehcache ライブラリーバージョンの検索が必要になる場合があることに注意してください。
4.2.2. Hibernate トランザクション リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
デフォルトでは、jBPM は "トランザクションごとのセッション" パターンを使用してトランザクションを Hibernate に委譲します。
jbpmContext で永続的な操作が呼び出されたときに初めてセッションが開かれると、jBPM は Hibernate トランザクションを開始します。トランザクションは、Hibernate セッションが閉じられる直前にコミットされます。これは jbpmContext.close() 内で実行されます。
jbpmContext.setRollbackOnly() を使用して、ロールバック対象のトランザクションをマークします。そうすることで、セッションが jbpmContext.close() メソッド内で閉じられる直前にトランザクションがロールバックされます。
Business Process Manager が Hibernate アプリケーションプログラミングインターフェイスを介してトランザクションメソッドを呼び出すことを禁止するには、isTransactionEnabled プロパティーを
false に設定します。これについては、「DbPersistenceServiceFactory」 で詳しく説明しています。
4.2.3. JTA トランザクション リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
マネージドトランザクションは、jBPM が JBoss Application Server で使用されている場合に最もよく見られます。次のコードサンプルは、トランザクションを JTA にバインドする一般的な方法を示しています。
<jbpm-context>
<service name="persistence">
<factory>
<bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
<field name="isTransactionEnabled"><false /></field>
<field name="isCurrentSessionEnabled"><true /></field>
<field name="sessionFactoryJndiName">
<string value="java:/myHibSessFactJndiName" />
</field>
</bean>
</factory>
</service>
</jbpm-context>
次に、データソースを使用するように Hibernate セッションファクトリーを設定して、Hibernate 自体を Transaction Manager にバインドします。複数のデータソースを使用する場合は、それらのデータベースを
XA datasource にバインドします。
<hibernate-configuration>
<session-factory>
<!-- hibernate dialect -->
<property name="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</property>
<!-- DataSource properties (begin) -->
<property name="hibernate.connection.datasource">
java:/JbpmDS
</property>
<!-- JTA transaction properties (begin) -->
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory
</property>
<property name="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.JBossTransactionManagerLookup
</property>
<property name="jta.UserTransaction">
java:comp/UserTransaction
</property>
</session-factory>
</hibernate-configuration>
注記
Hibernate を Transaction Manager にバインドする方法の詳細は、http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#configuration-optional-transactionstrategy を参照してください。
次に、
XA datasource を使用するように Hibernate を設定します。
これらの設定により、エンタープライズ Bean が CMT を使用できるようになり、Web コンソールが BMT を使用できるようになります。(jta.UserTransaction も指定されているのはそのためです。)
4.2.4. クエリーのカスタマイズ リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
jBPM が使用するすべての SQL クエリーは、1 つの中央設定ファイルにあります。このリソースファイルは、
hibernate.cfg.xml 設定ファイルで参照されます。
<hibernate-configuration>
<!-- hql queries and type defs -->
<mapping resource="org/jbpm/db/hibernate.queries.hbm.xml" />
</hibernate-configuration>
これらのクエリーの 1 つ以上をカスタマイズするには、元のファイルのバックアップを作成します。次に、カスタマイズしたバージョンをクラスパスの任意の場所に配置し、カスタマイズしたバージョンを参照するように
hibernate.cfg.xml の org/jbpm/db/hibernate.queries.hbm.xml への参照を更新します。
4.2.5. データベースの互換性 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
jBPM は、Hibernate でサポートされているすべてのデータベースで実行されます。
4.2.5.1. JDBC 接続の分離レベル リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
JDBC 接続のデータベース分離レベルを少なくとも
READ_COMMITTED に設定します。
警告
READ_UNCOMMITTED (分離レベルゼロ、Hypersonic でサポートされる唯一の分離レベル) に設定されている場合、ジョブエグゼキューター で競合状態が発生する可能性があります。これは、複数のトークンの同期が行われているときにも発生する可能性があります。
4.2.5.2. データベースの変更 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
別のデータベースを使用するように Business Process Manger を再設定するには、次の手順に従います。
- JDBC ドライバーライブラリーアーカイブをクラスパスに配置します。
- jBPM が使用する Hibernate 設定を更新します。
- 新しいデータベースにスキーマを作成します。
4.2.5.3. データベーススキーマ リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
jbpm.db サブプロジェクトには、ユーザーが選択したデータベースの使用を開始するのに役立つドライバー、手順、およびスクリプトが含まれています。詳細は、jbpm.db プロジェクトのルートにある readme.html を参照してください。
注記
JBPM は任意のデータベースの DDL スクリプトを生成できますが、これらのスキーマは常に効率的であるとは限りません。会社のデータベース管理者に生成された DDL を確認してもらい、列の型とインデックスを最適化できるようにすることを検討してください。
次の Hibernate 設定オプションは、開発環境で使用できます。hibernate.hbm2ddl.auto を
create-drop に設定すると、データベースがアプリケーションで初めて使用されるときに、スキーマが自動的に作成されます。アプリケーションが終了すると、スキーマは削除されます。
4.2.5.3.1. プログラムによるデータベーススキーマ操作 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
jBPM は、
org.jbpm.JbpmConfiguration のメソッド createSchema および dropSchema を介して、データベーススキーマを作成および削除するための API を提供します。これらのメソッドの呼び出しには、設定されたデータベースユーザーの権限以外に制約がないことに注意してください。
注記
前述の API は、クラス
org.jbpm.db.JbpmSchema によって提供される、より広範な機能へのファサードを構成します。
4.2.5.4. Hibernate クラスの組み合わせ リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Hibernate と jBPM の永続クラスを組み合わせると、2 つの大きなメリットが得られます。セッション、接続、およびトランザクションの管理が容易になります。これは、これらを 1 つの Hibernate セッションファクトリーに結合することで、Hibernate セッションと JDBC 接続が 1 つだけになるためです。したがって、jBPM の更新は、ドメインモデルの更新と同じトランザクションになります。これにより、Transaction Manager が不要になります。
第 2 に、Hibernate 永続オブジェクトを追加作業なしでプロセス変数にドロップできます。
これを実現するには、中央の
hibernate.cfg.xml ファイルを 1 つ作成します。デフォルトの jBPM hibernate.cfg.xml を出発点として使用し、独自の Hibernate マッピングファイルへの参照を追加してカスタマイズするのが最も簡単です。
4.2.5.5. jBPM Hibernate マッピングファイルのカスタマイズ リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
次の手順に従って、jBPM Hibernate マッピングファイルをカスタマイズします。
- ソース (
src/jbpm-jpdl-sources.jar) から jBPM Hibernate マッピングファイルをコピーします。 - コピーをクラスパスの任意の場所に配置します (以前と同じ場所でないことを確認します)。
hibernate.cfg.xml内のカスタマイズしたマッピングファイルへの参照を更新します。
4.2.5.6. 2 次キャッシュ リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
jBPM は Hibernate の 二次キャッシュ を使用して、一度ロードされたプロセス定義をメモリーに保持します。プロセス定義のクラスとコレクションは、キャッシュ要素が次のようになるように、Hibernate マッピングファイルで設定されます。
<cache usage="nonstrict-read-write"/>
プロセス定義は決して変更されないため、2 次キャッシュに保持しても問題ありません。(「 デプロイされたプロセス定義の変更 」 も併せて参照してください。)
デフォルトのキャッシュストラテジーは、
nonstrict-read-write に設定されています。ランタイム実行時に、プロセス定義が静的なままとなるため、最大限のキャッシュを実現できます。理論的には、read-only キャッシュストラテジーのほうがランタイム実行にはさらに適していますが、その設定では新しいプロセス定義のデプロイメントが許可されません。
この章では、Hibernate を最大限に活用する方法など、jBPM の永続性のトピックに関連する多くの理論的情報と実践的なアドバイスを説明しました。