JBPM導入

第1章はじめに
JBOSS jBPMは、柔軟でスケーラブルなワークフロー管理システムです。 JBoss jBPMには、タスク、非同期待機状態、タイマー、自動化アクションなどを含むビジネスフロー図を表現する直感的なプロセス言語があります。これらの操作をバンドルすることで、JBoss jBPMは非常に強力でスケーラブルな制御フローメカニズム。
JBoss JBPMは依存性が最も小さく、Javaライブラリと同じくらい簡単に使用できます。 また、スループットに重大な影響を与える環境で使用されるJ2EEクラスタアプリケーションサーバーにもデプロイできます。
JBOSS jBPMは任意のデータベースとして設定でき、任意のアプリケーションサーバーに展開できます。
1.1概要コアワークフローとBPM機能は、データベースに情報を格納し、プロセスを更新するサービスを含むシンプルなJavaライブラリとしてパッケージ化されています。

図1.1 JBossのjBPMコンポーネントの概要
1.2 JBoss jBPMスターターキットスターターキットは、以下を含むすべてのjBPMコンポーネントを含むダウンロードパッケージです。
Jbpm-serverは、あらかじめ設定されたjbossアプリケーションサーバーです。
l Jbpm - デザイナー、グラフィカルデザインのjBPMプロセスのEclipseプラグイン。
Jbpm-db、jBPMデータベース互換パッケージ(下記参照)。
Jbpm、ライブラリとこのガイドを含むコアjbpmコンポーネント。
Jbpm-bpel、JBOSS jBPM BPEL拡張リファレンス。
事前設定済みのJBossアプリケーションサーバーには、以下のコンポーネントがインストールされています。
lコアjBPMコンポーネント。サービスファイルとしてパッケージ化されています。
l jBPMライブラリテーブルを含む統合データベース:デフォルトの極超音速データベースには、jBPMテーブルと1つのプロセスが追加されています。
jBPMコンソールWebアプリケーション。プロセス参加者またはjBPM管理者が使用できます。
lタイマ実行用のjBPMスケジューラ。 スケジューラはスタータキットのサーブレットとして構成され、タイマを監視して実行するためのスレッドを生成します。
lコマンドの非同期実行のためのjBPMコマンド実行プログラム。 Command Executorはサーブレットとしても構成されており、コマンドを監視して実行するためのスレッドを生成します。
プロセスインスタンスがjBPMデータベースにデプロイされています。
1.3 JBOSS jBPMグラフィカルプロセスデザイナー
JBoss jBPMには、ビジネスプロセスをオーサリングするグラフィカルなツールであるグラフィカルデザインツールも含まれています。
JBOSSのjBPMグラフィカルプロセスデザイナーは、すでに開発目標にデザイナーとは別にインストール可能なEclipseプラグインです。
グラフィカルデザイナーの非常に重要な機能は、ビジネスアナリストとテクノロジー開発者の両方をサポートし、ビジネスプロセスモデリングから実際の実装にスムーズに移行できることです。
プラグインは、ローカルの更新設定(通常のzipファイル)として使用でき、標準のEclipseソフトウェア更新メカニズムを使用してインストールできます。 パッケージもあり、Eclipseホーム・ディレクトリーに直接抽出することができます。
1.4 JBOSSのjBPMコアコンポーネント
JBoss jBPMコアコンポーネントは、プロセスインスタンスのプロセス定義と実行環境を管理するための一般的なJava(J2SE)ソフトウェアです。
JBOSS jBPMはJavaライブラリであるため、Webアプリケーション、スイングアプリケーション、EJB、WebサービスなどのJava環境で使用できます。jBPMライブラリは、ステートレスセッションEJBとしてパッケージ化することもでき、非常に高いスループットを実現します。 ステートレスセッションEJBは、任意のアプリケーションサーバーにデプロイできるように、J2EE 1.3仕様に従って記述されています。
jbpm-3.0.jarライブラリは、hibernate、dom4jなどのサードパーティのライブラリに依存しています。これらのライブラリのすべては、第5章「配備」にリストされています。また、JBoss jBPMコアコンポーネントは、 TODOの明確な説明。
永続化するために、従来のO / Rマッピングに加えて、jBPMの内部使用の休止状態は、異なるデータベース(ダイアレクト)間のSQLダイアレクトを解決するので、jBPMは現在のすべてのデータベースで簡単に移植できます。
JBOSS jPBM APIは、Webアプリケーション、EJB、Webサービスコンポーネント、メッセージドリブンBean、その他のJavaコンポーネントなど、プロジェクト内のカスタムJavaソフトウェアからアクセスできます。
1.5 JBOSS jBPMコンソールWebアプリケーション
jBPMコンソールWebアプリケーションには2つの目的があります。 まず、プロセス実行によって生成されたランタイム・タスクと対話する重要なユーザー・インターフェースとして機能し、次にランタイム・インスタンスを調べて操作できる管理およびモニター・コンソールです。
1.6 JBOSS jBPMアイデンティティコンポーネント
JBoss jBPMは、ユーザー情報や他の組織情報ディレクトリを含む企業と統合しますが、JBoss jBPMには、組織情報コンポーネントがないプロジェクト用の独自のコンポーネントが含まれています。 アイデンティティ・コンポーネントは、サーブレット、ejb、およびポートレットよりも伝統的なモデルを使用します。ポートレットは、サーブレットに似たポータルの最も重要なコンポーネントであり、ポートレットは、動的コンテンツを生成するためにコンテナにデプロイされるWebコンポーネントです。リッチ。
詳細は、「11.11 IDコンポーネント」を参照してください。 TODO
1.7 JBOSS jBPMスケジューラ
JBOSS jBPMスケジューラは、タイマーを監視および実行し、プロセスの実行中にスケジュールされるコンポーネントです。
タイマコンポーネントソフトウェアはコアjbpmライブラリにパッケージ化されていますが、監視スレッドを生成するようにスケジューラサーブレットを設定するか、ディスパッチャのmainメソッドで別のJVMを起動するかのいずれかの環境で展開する必要があります。
1.8 JBOSS jBPMデータベース互換パッケージ
JBOSS jBPM Database Compatibility Packは、jBPMを任意のデータベースで実行できるようにするすべての情報、ドライバ、およびスクリプトを含むダウンロードパッケージです。
1.9 JBOSS jBPM BPEL拡張
JBoss jBPM BPEL拡張は、BPEL(Business Process Execution Language)をサポートするためにjBPMを拡張するスタンドアロン拡張です。BPELは基本的に、他のWebサービスに基づいてWebサービスを構築するために使用されるxmlスクリプト言語です。 Webサービスを作成します。
第3章ガイドラインこのガイドでは、jpdlを使用して基本的なプロセスを作成する方法、およびAPIを使用してランタイム実行を管理する方法を説明します。
このガイドは、特定のトピックに焦点を当て、多数のコメントを含む一連のサンプルの形式を取っています(jBPMダウンロードパッケージのsrc / java.examplesディレクトリにもあります)。
学習する最善の方法は、プロジェクトを構築して、与えられた例に対してさまざまな変更を加えて実験することです。
Eclipseを使用する場合は、jbpm-3.0- [version]をダウンロードして、自分のシステムに解凍してから、「File」 - >「Import ...」 - >「Existing Project into Workspace」を実行します。次に "Next"をクリックし、jBPMルートを探して "Finish"をクリックします。 作業スペースにjbpm.3プロジェクトがあるので、このガイドの例はsrc / java.examples /にあります。これらの例を開くとメニュー "Run"を使うことができます - - > Run As ... - > JUnit Testを実行します。
jBPMには、例に示すXMLを作成するためのグラフィカルデザイナツールが含まれています。このツールのダウンロード手順は、「2.1ダウンロード概要」にありますが、このガイドを完成させるためのグラフィカルデザイナツールは必要ありません。
3.1 Hello Worldの例プロセス定義はノードと変換からなる有向グラフです。 Hello worldここでは3つのノードがありますが、どのように組み立てられているかを見ていきましょう。デザイナーツールを使用せずに簡単なプロセスから始めましょう。以下の図は、hello worldプロセスのグラフ表示です。

図3.1 hello worldのフローチャート
public void testHelloWorldProcess(){
//このメソッドは、プロセス定義とプロセス定義の実行を示します。
//このプロセス定義には3つのノードがあります:名前のない開始状態、
//状態「s」と、終了状態「end」とを含む。
//次の行は、ProcessDefinitionオブジェクト(プロセス定義)に対するxmlテキストを解析します。
// ProcessDefinition Javaオブジェクトとしてのプロセスの正規化された記述。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<プロセス定義>" +
"<開始状態>" +
"<= 's' />への移行+
"</ start-state>" +
"<state name = 's'>" +
"<= 'end' />への遷移+
"</ state>" +
"<終了状態名= '終了' />」+
"</ process-definition>"
);

//この行は、実装のプロセス定義を作成するためのものです。 作成されると、1つのプロセスが実行されます
//メイン実行パス(=ルートトークン)。開始状態に配置されます。
ProcessInstance processInstance =
新しいProcessInstance(processDefinition);

//作成されると、プロセス実行にはメイン実行パス(=ルートトークン)があります。
トークントークン= processInstance.getRootToken();

//作成されると、メイン実行パスはプロセス定義の先頭に配置されます。
assertSame(processDefinition.getStartState()、token.getNode());

//プロセスの実行を開始し、開始状態をデフォルト遷移にします。
token.signal();
シグナルメソッド//は、待機状態のプロセスをブロックします。

//プロセス実行が最初の待機状態 "s"に入り、主実行パスが位置付けられるようにする
//状態 "s"にある。
assertSame(processDefinition.getNode( "s")、token.getNode());

//別の信号を送りましょう。これは、デフォルトで状態 "s"変換を使用します
//ステータス "s"のままにして、プロセスの実行を再開します。
token.signal();
//プロセスの例が終了状態に達したため、シグナルメソッドが返されるようになりました。
assertSame(processDefinition.getNode( "end")、token.getNode());
}

3.2データベースの例
jBPMの機能の1つは、プロセスが待機している間にプロセスの実行をデータベースに保持する機能です。 次の例では、プロセスインスタンスをデータベースに格納する方法を示します。この例ではコンテキストが表示されます。 後で、メッセージドリブンBeanはデータベースからプロセスインスタンスをロードし、実行を再開します。たとえば、コードの一部がWebアプリケーションでプロセスを開始し、データベースに保存されます。
jBPM永続性の詳細については、第7章永続性を参照してください。
パブリッククラスHelloWorldDbTestはTestCase {

静的JbpmConfiguration jbpmConfiguration = null;

静的{
// "src / config.files"にあるような設定ファイルの例を見つけることができます。
//通常、設定情報はリソースファイル "jbpm.cfg.xml"にありますが、ここでは
// XML文字列を介して設定情報を渡します。
//最初に静的なJbpmConfigurationを作成します。 JbpmConfiguration
//システム内のすべてのスレッドが使用できるため、安全に設定できます
//静的な理由です。

jbpmConfiguration = JbpmConfiguration.parseXmlString(
"<jbpm-configuration>" +

// jbpm-contextメカニズムは、jbpmコアエンジンを外部環境によって提供されるサービスから分離します。

"<jbpm-context>" +
"<サービス名= '永続性'" +
"factory = 'org.jbpm.persistence.db.DbPersistenceServiceFactory' />" +
"</ jbpm-context>" +

//また、jbpmによって使用されるすべてのリソースファイルは、jbpm.cfg.xmlで提供されます。

"<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(){
//すべてのデータは、以下の3つのメソッドの間でデータベースに渡されます。
//このテストでは、これらの3つのメソッドは、
//完全なプロセスシナリオ。 しかし実際、これらの方法はサーバーとの違いを表しています
//リクエストします。
//クリーンで空のデータベースから始めたので、まずプロセスを展開する必要があります。
//実際、これはプロセス開発者が一度だけ行う必要があります。
deployProcessDefinition();

//ユーザーがWebアプリケーションでフォームを送信したときにプロセスを開始すると仮定します
//インスタンス(=プロセス実行)...
processInstanceIsCreatedWhenUserSubmitsWebappForm();

//そして、非同期メッセージが到着して実行を継続します。
theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
}

public void deployProcessDefinition(){
//このテストは、プロセス定義とプロセス定義の実行を示します。
//このプロセス定義には3つのノードがあります:名前のない開始状態、
//状態「s」と、終了状態「end」とを含む。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<プロセス定義名= 'hello world'>" +
"<開始状態名= '開始'> '+
"<= 's' />への移行+
"</ start-state>" +
"<state name = 's'>" +
"<= 'end' />への遷移+
"</ state>" +
"<終了状態名= '終了' />」+
"</ process-definition>"
);

//上で設定したpojo永続コンテキスト作成者を探します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
//プロセス定義をデータベースにデプロイします。
jbpmContext.deployProcessDefinition(processDefinition);

} finally {
// pojo永続コンテキストを閉じます。 これには、SQLステートメントをプロセスにフラッシュすることも含まれます
//定義をデータベースに挿入します。
jbpmContext.close();
}
}

public void processInstanceIsCreatedWhenUserSubmitsWebappForm(){
//このメソッドのコードは、strutsのactiongに置くことも、JSFで管理することもできます
// bean。

//上で設定したpojo永続コンテキスト作成者を探します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{

GraphSession graphSession = jbpmContext.getGraphSession();

ProcessDefinition processDefinition =
graphSession.findLatestProcessDefinition( "hello world");

//データベースから取得したプロセス定義を使用してプロセス定義の実行を作成する
// hello worldの例のように(この例は永続化されません)。
ProcessInstance processInstance =
新しいProcessInstance(processDefinition);

トークントークン= processInstance.getRootToken();
assertEquals( "start"、token.getNode()。getName());
//プロセスの実行を開始しましょう
token.signal();
//プロセスは状態 's'になりました。
assertEquals( "s"、token.getNode()。getName());

//処理インスタンスprocessInstanceがデータベースに保存され、
//プロセス実行の現在の状態もデータベースに格納されます。
jbpmContext.save(processInstance);
//そして、データベースからプロセスインスタンスを再度取得し、別のインスタンスを提供することで
//プロセスの実行を再開するためのシグナル。

} finally {
// pojo永続コンテキストを閉じます。
jbpmContext.close();
}
}

public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived(){
//このメソッドのコードは、メッセージ駆動型Beanのコンテンツとして使用できます。

//上で設定したpojo永続コンテキスト作成者を探します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{

GraphSession graphSession = jbpmContext.getGraphSession();
//まず、データベースからプロセスインスタンスを取得する必要があります。
//ここで扱っているプロセスインスタンスを伝えるためのいくつかの代替方法があります。
//この簡単なテストで最も簡単な方法は、プロセスインスタンスのリスト全体を調べ、
//ここには結果だけが与えられるはずです。

//まず、プロセス定義を見つけましょう。

ProcessDefinition processDefinition =
graphSession.findLatestProcessDefinition( "hello world");

//このプロセスで定義されたすべてのプロセスインスタンスを検索します。
リストprocessInstances =
graphSession.findProcessInstances(processDefinition.getId());

//このユニットテストでは実行が1つしかないことがわかっているからです。
//実際には、到着したコンテンツからprocessInstanceIdを抽出することができます
//またはユーザーが選択を行う。
ProcessInstance processInstance =
(ProcessInstance)processInstances.get(0);

//今度は続けることができます。 注:processInstanceは委託されたシグナルになります
//メイン実行パス(=ルートトークン)に移動します。
processInstance.signal();

//このシグナルの後、プロセスの実行が終了状態に達しているはずです。
assertTrue(processInstance.hasEnded());

//データベースの実行状態を更新できるようになりました。
jbpmContext.save(processInstance);

} finally {
// pojo永続コンテキストを閉じます。
jbpmContext.close();
}
}
}

3.3コンテキストの例プロセス変数プロセス変数には、プロセス実行中のコンテキスト情報が含まれています。java.util.Mapに似ています。変数名と値、javaオブジェクト、プロセス変数の一部として保持されています。 。 ここでの例では、変数を使用するAPIを永続性なしで表示しています。
変数の詳細は、「第10章コンテキスト」を参照してください。
//この例はまだhello worldプロセスから始まり、変更はありません。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<プロセス定義>" +
"<開始状態>" +
"<= 's' />への移行+
"</ start-state>" +
"<state name = 's'>" +
"<= 'end' />への遷移+
"</ state>" +
"<終了状態名= '終了' />」+
"</ process-definition>"
);

ProcessInstance processInstance =
新しいProcessInstance(processDefinition);

//プロセスインスタンスからコンテキストインスタンスを取得して、プロセス変数を使用します。
ContextInstance contextInstance =
processInstance.getContextInstance();

//プロセスが開始状態になる前に、プロセスインスタンスのコンテキスト内になければなりません
//いくつかのプロセス変数を設定します。
contextInstance.setVariable( "amount"、新しい整数(500));
contextInstance.setVariable( "reason"、 "私のデッドラインに会った");

//以降、これらのプロセス変数はプロセスインスタンスに関連付けられます。 ショーは今ユーザコードによって渡されます
// APIはプロセス変数にアクセスし、アクションまたはノードの実装にコードが存在することができます。
//プロセス変数は、プロセスインスタンスの一部としてデータベースにも格納されます。
processInstance.signal();

// contextInstanceを介してプロセス変数にアクセスします。

assertEquals(新しい整数(500)、
contextInstance.getVariable( "amount"));
assertEquals(「私のデッドラインに会った」、
contextInstance.getVariable( "reason"));

3.4タスク割り当ての例次の例では、タスクをユーザに割り当てる方法を示します。 jBPMワークフローエンジンは組織モデルとは独立しているため、参加者を評価するための言語は限られているため、タスク参加者の計算を含むAssignmentHandlerの実装を指定する必要があります。
public void testTaskAssignment(){
//次のプロセスは、hello worldプロセスに基づいています。 状態ノードは、タスクノードノード
//置き換えられました。 task-node待機状態を表し、生成されるJPDL内のノードのクラス。
//処理が続行される前に実行されるタスク。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<プロセス定義名= 'ベビープロセス'>" +
"<開始状態>" +
"<transition name = 'baby cries' to = 't' />" +
"</ start-state>" +
"<タスクノード名= 't'>" +
"<task name = 'change nappy'>" +
"<assignment class = 'org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' />" +
"</ task>" +
"<= 'end' />への遷移+
"</ task-node>" +
"<終了状態名= '終了' />」+
"</ process-definition>"
);

//プロセス定義の実行を作成します。
ProcessInstance processInstance =
新しいProcessInstance(processDefinition);
トークントークン= processInstance.getRootToken();

//プロセスの実行を開始し、デフォルトでは開始状態にします
token.signal();
//シグナルメソッドは待機状態のプロセスをブロックし、
//ここで、タスクノードでブロックされます。
assertSame(processDefinition.getNode( "t")、token.getNode());

//実行がtask-nodeに到達すると、 'change nappy'タスクが作成され、
// NappyAssignmentHandlerが呼び出され、タスクの割り当て先を決定します。
// NappyAssignmentHandlerは 'papa'を返します。

//実際の環境では、org.jbpm.db.TaskMgmtSessionのメソッドが使用されます
//データベースからタスクを取得します。 この例では複雑な永続性を含めたくないため、
//このプロセスインスタンスの最初のタスクインスタンスのみを使用します(この
//テストシナリオ、1つのタスクのみ)。
TaskInstance taskInstance =(TaskInstance)
processInstance
.getTaskMgmtInstance()
.getTaskInstances()
.iterator()。next();

//ここで、taskInstanceが実際に 'papa'に割り当てられているかどうかを確認します。
assertEquals( "papa"、taskInstance.getActorId());

//ここで、 'パパ'が自分の仕事を完了し、仕事を完了したと仮定しよう。
taskInstance.end();
//これは最後に実行されるタスク(唯一のタスク)であるため、タスクの完了
//プロセスインスタンスの継続をトリガーします。

assertSame(processDefinition.getNode( "end")、token.getNode());
}

3.5カスタムアクションの例アクションは、独自のカスタムコードをjBPMプロセスにバインドするメカニズムです。 アクションは、プロセスのグラフィカル表現に関連している場合は、そのノードに関連付けることができます。 アクションは、変換の実行、ノードからの退出、またはノードへの入力などのイベントに配置することもできます。この場合、アクションはグラフィカル表現の一部ではなく、プロセス実行中にトリガーイベントが実行されたときに実行されます。
この例で使用するアクションの実装を見てみましょう:MyActionHandler、このアクション処理の実装は実際に何もしません。ブール変数isExecutedをtrueに設定するだけです。 変数isExecutedは静的変数であるため、アクションプロセス(つまりメソッド内部)から内部的にアクセスすることも、アクション(つまりアクションクラス)から検証することもできます。
アクションの詳細については、「9.5アクション」を参照してください。
// MyActionHandlerは、jBPMプロセスの実行中にユーザーコードを実行できるクラスです。
パブリッククラスMyActionHandlerはActionHandler {

//(setUpメソッド内の)各テストの前に、isExecutedメンバはfalseに設定されます。
public static boolean isExecuted = false;

//アクションはisExecutedをtrueに設定します。アクションが実行されるとユニットテストが実行されます
//表示する。
public void execute(ExecutionContext executionContext){
isExecuted = true;
}
}
前述のように、各テストの前に、静的フィールドMyActionHandler.isExecutedをfalseに設定します。
//各テストは、MyActionHandlerを設定する静的メンバーを使用してisExecutedになります。
// falseで始まります。
public void setUp(){
MyActionHandler.isExecuted = false;
}
私たちはコンバージョンを開始します。
public void testTransitionAction(){
//以下のプロセスはhello worldプロセスとは異なります。 私たちは国家「s」から
//状態変換の最後にアクションが追加されました。 このテストの目的は、
// JavaコードをjBPMプロセスに統合するのは簡単です。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<プロセス定義>" +
"<開始状態>" +
"<= 's' />への遷移+
"</ start-state>" +
"<state name = 's'>" +
"<transition to = 'end'>" +
"<action class = 'org.jbpm.tutorial.action.MyActionHandler' />" +
"</ transition>" +
"</ state>" +
"<終了状態名= '終了' />」+
"</ process-definition>"
);

//プロセス定義の新しい実行を開始しましょう。
ProcessInstance processInstance =
新しいProcessInstance(processDefinition);

//次のシグナルは、実行を開始状態のままにし、状態 "s"にする。
processInstance.signal();

// MyActionHandlerがまだ実行されていないことを示します。
assertFalse(MyActionHandler.isExecuted);
// ...実行のメインパスは状態 "s"にあります。
assertSame(processDefinition.getNode( "s")、
processInstance.getRootToken()。getNode());

//次のシグナルはルートトークンの実行をトリガーし、トークンはアクションを伴う変換を実行し、
//シグナルメソッドトークンの呼び出し中にアクションが実行されます。
processInstance.signal();

//シグナルメソッドの呼び出し中にMyActionHandlerが実行されたことがわかります。
assertTrue(MyActionHandler.isExecuted);
}
次の例は同じアクションを示していますが、アクションはそれぞれenter-nodeイベントとleave-nodeイベントに配置されます。 ノードにはコンバージョンよりも多くのイベントタイプがあり、コンバージョンが1つしかないため、ノード上にアクションを配置してイベント要素に配置する必要があります。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
"<プロセス定義>" +
"<開始状態>" +
"<= 's' />への遷移+
"</ start-state>" +
"<state name = 's'>" +
"<event type = 'node-enter'>" +
"<action class = 'org.jbpm.tutorial.action.MyActionHandler' />" +
"</ event>" +
"<event type = 'node-leave'>" +
"<action class = 'org.jbpm.tutorial.action.MyActionHandler' />" +
"</ event>" +
"<= 'end' />への遷移+
"</ state>" +
"<終了状態名= '終了' />」+
"</ process-definition>"
);

ProcessInstance processInstance =
新しいProcessInstance(processDefinition);

assertFalse(MyActionHandler.isExecuted);
//次のシグナルは、実行を開始状態から終了し、状態 "s"に移ります。
//状態 's'が入力されると、アクションが実行されます。
processInstance.signal();
assertTrue(MyActionHandler.isExecuted);

// MyActionHandler.isExecutedをリセットします。
MyActionHandler.isExecuted = false;

//次のシグナルは実行をトリガーしてステータス 's'を残し、アクションが実行されます。
processInstance.signal();
//見る
assertTrue(MyActionHandler.isExecuted);

第5章導入
jBPMは組み込みBPMエンジンです。つまり、スタンドアロンのソフトウェア製品をインストールしている場合とまったく同じようにjBPMを独自のJavaプロジェクトに組み込むことができ、依存性を最小限に抑えるための主要な機能の1つです。ライブラリとその依存関係
5.1 Java実行環境
jBPM3にはJ2SE1.4.2 +
5.2 jBPMライブラリ
jbpm- [version] .jarはコアフィーチャーライブラリです。
jbpm-identity- [version] .jarは、「11.11アイデンティティコンポーネント」(オプション)で説明したアイデンティティコンポーネントを含むライブラリです。
5.3サードパーティのライブラリ最小限の配備では、jBPMを使用して、commons-loggingおよびdom4jライブラリをクラスパスに配置するだけでプロセスを作成および実行できますが、これはプロセスの永続性をサポートしていません。 xml解決のプロセスを使用しない場合は、dom4jライブラリを削除してプログラミングし、オブジェクト図を作成することができます。
表5.1
ライブラリ目的説明カタログ
commons-logging.jar jBPMとhibernateレコードの日付。 jBPMコードログはコモンログに記録されます。コモンログライブラリは、ログをjava1.4ログ、log4j、...などに配布するよう設定できます。コモンログを設定する方法の詳細については、apache commonsユーザーガイドを参照してください。 log4jを使用している場合、最も簡単な方法は、log4jライブラリとlog4j.propertiesをクラスパス上に置くことです。コモンログは自動的にその設定を検出して使用します。 lib / jboss(jboss4.0.3より)
Dom4j-1.6.1.jarプロセス定義とHibernate永続性 Xmlの解像度。 lib / dom4j
jBPMの典型的な配備には、プロセス定義とプロセス実行の永続性が含まれます。この場合、jBPMは、hibernateとそれが依存するライブラリ以外の依存関係を失います。
もちろん、ライブラリーは、使用する環境や機能に応じて、必要なものを休止します。詳細については、休止状態の資料を参照してください。 次の表に、通常のPOJOデプロイメント環境の手順を示します。
jBPMリリースでは、hibernate3.1を使用していますが、3.0.xでも動作します。もしそうなら、hibernate.queries.hbm.xml設定ファイルでいくつかのhibernateクエリを更新する必要があります。 7.6カスタムクエリ。
表5.2
ライブラリ目的説明カタログ
hibernate3.jarは永続性を維持します。 最高のO / Rマッパー。 lib / hibernate(hibernate3.1)
antlr-2.7.5H3.jarは、Hibernate永続性クエリ分析で使用されます。 ライブラリを解析します。 lib / jboss(jboss4.0.3より)
cglib-2.1_2jboss.jar hibernate永続性。 hibernateプロキシで使用されるReflexライブラリ。 lib / jboss(jboss4.0.3より)
Commons-collection.jarは永続性を維持します。 lib / jboss(jboss4.0.3より)
ehcache-1.1.jar hibernate persistence(デフォルト設定)。 セカンドレベルのキャッシュ実装では、異なるキャッシュを休止状態に設定すると、ライブラリは必要ありません。 lib / hibernate
jaxen-1.1-beta-4.jarプロセス定義とhiberante永続性。 XPathライブラリ(dom4jで使用)。 lib / hibernate
jdbc2_0-stdext.jarは永続性を維持します。 lib / hibernate
asm.jarは永続性を維持します asmバイトコードライブラリ。 lib / hibernate
asm-attrs.jarは永続性を維持します。 asmバイトコードライブラリ。 lib / hibernate
beanshellライブラリはオプションです。これをインクルードしないと、beanshellをjbpmプロセス言語に統合することができなくなり、 "jbpmがスクリプトクラスをロードできないため、スクリプト要素を使用できません"というログメッセージが表示されます。
表5.3
ライブラリ目的説明カタログ
bsh-1.3.0.1.jar beanshellスクリプトインタプリタ。 これらのプロセス要素を使用していないときは、スクリプトや決定要素でのみ使用されるbeanshellライブラリを削除できますが、hibernate.cfg.xmlファイルのSceipt.hbm.xmlマッピング行をコメントアウトする必要があります。 lib / jboss

第6章設定
jBPM設定はjavaクラスorg.jbpm.JbpmConfigurationによって記述され、JbpmConfigurationを取得する最も簡単な方法は、シングルトンインスタンスメソッドJbpmConfiguration.getInstance()を使用することです。
別のソースから構成をロードする場合は、JbpmConfiguration.parseXxxxメソッドを使用できます。
静的JbpmConfinguration jbpmConfiguration = JbpmConfinguration.getInstance();
JbpmConfigurationはスレッドセーフなので、スタティックメンバに保持することができ、すべてのスレッドはJbpmConfigurationをJbpmContextオブジェクトのファクトリとして使用できます。 JbpmContextはトランザクションを表し、コンテキストブロックJbpmContextサービスが利用可能な場合、コンテキストブロックは次のようになります。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
//コンテキストブロックと呼ばれるものです。
//ワークフロー操作を実行できます

} finally {
jbpmContext.close();
}
JbpmContextは、一連のサービスと構成をjBPMとして利用可能にします。これはjbpm.cfg.xml構成ファイルで構成され、jBPMをJava環境で使用できるようにします。
src / config.files / jbpm.cfg.xmlにあるように、JbpmContextの典型的な設定を以下に示します。
<jbpm-configuration>

<jbpm-context>
<サービス名= '永続性' factory = 'org.jbpm.persistence.db.DbPersistenceServiceFactory' />
<service name = 'message' factory = 'org.jbpm.msg.db.DbMessageServiceFactory' />
<service name = 'scheduler' factory = 'org.jbpm.scheduler.db.DbSchedulerServiceFactory' />
<service name = 'logging' factory = 'org.jbpm.logging.db.DbLoggingServiceFactory' />
<サービス名= '認証' factory = 'org.jbpm.security.authentication.DefaultAuthenticationServiceFactory' />
</ jbpm-context>

<! - jbpm- {version}のデフォルト構成ファイルを指す構成リソースファイル.jar - >
<string name = 'resource.hibernate.cfg.xml' value = 'hibernate.cfg.xml' />
<! - <string name = 'resource.hibernate.properties' value = 'hibernate.properties' /> - >
<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.parsers' value = 'org / jbpm / jpdl / par / jbpm.parsers.xml' />
<string name = 'resource.varmapping' value = 'org / jbpm / context / exe / jbpm.varmapping.xml' />

<int name = 'jbpm.byte.block.size' value = "1024" singleton = "true" />
<bean name = 'jbpm.task.instance.factory' class = 'org.jbpm.taskmgmt.impl.DefaultTaskInstanceFactoryImpl' singleton = 'true' />
<bean name = 'jbpm.variable.resolver' class = 'org.jbpm.jpdl.el.impl.JbpmVariableResolver' singleton = 'true' />
<long name = 'jbpm.msg.wait.timout' value = '5000' singleton = 'true' />

</ jbpm-configuration>
この構成では、次の3つの部分を確認できます。
最初の部分では、一連のサービスを使用してコンフィグレーションjbpmコンテキストを実装しています。これらのコンフィグレーションのオプションについては、後で特定のサービス実装について説明します。
2番目の部分は、すべての構成リソースの参照マッピングです。一部の構成ファイルをカスタマイズする場合は、これらのリソース参照を変更できます。 通常、jbpm-3.x.jarのデフォルト設定をコピーしてクラスパスのどこかに置き、このファイルのカスタムバージョンの設定を変更することができます。
3番目の部分は、jbpmで使用されるエイリアス設定です。これらの設定オプションは、特定のトピックを含むセクションで説明しています。
サービスグル​​ープのデフォルト設定はシンプルなWebアプリケーション環境にあり、最小の依存性、永続性サービスがjdbc接続を取得し、他のすべてのサービスが同じ接続を使用してサービスを完成させるため、ワークフローすべての操作はJDBC接続のトランザクションに集中し、もはやトランザクションマネージャは不要です。
JbpmContextには、ほとんどのプロセス操作に便利なメソッドが含まれています。
public void deployProcessDefinition(ProcessDefinition processDefinition){...}
public List getTaskList(){...}
publicリストgetTaskList(String actorId){...}
public List getGroupTaskList(リストactorIds){...}
パブリックTaskInstance loadTaskInstance(long taskInstanceId){...}
パブリックTaskInstance loadTaskInstanceForUpdate(long taskInstanceId){...}
publicトークンloadToken(long tokenId){...}
publicトークンloadTokenForUpdate(long tokenId){...}
public ProcessInstance loadProcessInstance(long processInstanceId){...}
public ProcessInstance loadProcessInstanceForUpdate(long processInstanceId){...}
public ProcessInstance newProcessInstance(String processDefinitionName){...}
public void save(ProcessInstance processInstance){...}
public void save(トークントークン){...
public void save(TaskInstance taskInstance){...}
public void setRollbackOnly(){...}
XxxForUpdateメソッドは、ロードされたオブジェクトが自動的に保存されることを記録するので、saveメソッドを再度呼び出す必要はありません。
複数のjbpmコンテキストを指定することは可能ですが、各jbpmコンテキストのname属性は一意でなければならず、JbpmConfiguration.createContext(String name)を使用して名前付きコンテキストを取得できるようにする必要があります。
service要素は、このサービスのサービス名とサービスファクトリを定義します。このサービスは、JbpmContext.getServices()。getService(String name)を使用して要求された場合にのみ作成されます。
ファクトリは、属性を使用する代わりに要素として指定することもできます。 これは、呼び出されたオブジェクトファクトリを作成してアセンブルするためにXMLのコンポーネントを解析するファクトリオブジェクトにいくつかの設定情報を注入するために使用できます。
6.1構成プロパティー
jbpm.byte.block.size:添付ファイルとバイナリ変数は、blobではなく、バイナリオブジェクトの固定サイズのリストとしてデータベースに格納されます。これは、異なるデータベースで簡単に使用でき、jBPMの完全埋め込み機能を向上させます。固定長ブロックのサイズを制御します。
jbpm.task.instance.factory:カスタム・タスク・インスタンスを作成し、この属性にクラス全体の名前を指定します。これは、TaskInstance Beanをカスタマイズして新しい属性を追加する場合に必要です。 「11.10カスタムタスクインスタンス」を参照してください。指定されたクラスはorg.jbpm.tskmgmt.TaskInstanceFactoryを実装する必要があります。
jbpm.variable.resolver:定制jBPM在JSF表达式中寻找第一个术语的方式。
jbpm.msg.wait.timout:定制消息缓存的时间。
6.2 配置文件下面是对在jBPM中定义的所有配置文件的简短描述。
6.2.1 Hibernate.cfg.xml文件这个文件包含hibernate配置,并且引用hibernate映射资源文件。
位置:hibernate.cfg.xml文件如果不另外在jbpm.properties文件的jbpm.hibernate.cfg.xml属性中指定,则jBPM工程中的默认hibernate配置文件在目录src/config.files/hibernate.cfg.xml。
6.2.2 Hibernate查询配置文件这个文件包含jBPM会话org.jbpm.db.*Session中所使用的hibernate查询。
位置:org/jbpm/db/hibernate.queries.hbm.xml。
6.2.3 节点类型配置文件这个文件包含了XML节点元素到节点实现类的映射。
位置:org/jbpm/graph/node/node.types.xml。
6.2.4 动作类型配置文件这个文件包含了XML动作元素到动作实现类的映射。
位置:org/jbpm/graph/action/action.types.xml。
6.2.5 业务日历配置文件包含了业务时间和空闲时间的定义。
位置:org/jbpm/calendar/jbpm.business.calendar.properties。
6.2.6 变量映射配置文件指定了流程变量(java对象)的值怎样转换到用于存储到jbpm数据库中的变量实例。
位置:org/jbpm/context/exe/jbpm.varmapping.xml。
6.2.7 转换器配置文件指定了id到类名的映射。id被存储到数据库,org.jbpm.db.hibernate.ConverterEnumType被用来映射id到单态对象。
位置:org/jbpm/db/hibernate/jbpm.converter.properties。
6.2.8 缺省模块配置文件指定哪个模块被缺省添加到一个新的流程定义ProcessDefinition。
位置:org/jbpm/graph/def/jbpm.default.modules.properties。
6.2.9 流程档案解析器配置文件指定流程档案解析的解析器。
位置:org/jbpm/jpdl/par/jbpm.parsers.xml。
6.3 对象工厂对象工厂可以依照bean的xml配置文件创建对象,配置文件指定了对象将被怎样创建、配置以及组装到一起形成一个完整的对象图。对象工厂可以注入配置和其他bean到一个bean中。
在最简单的形式中,对象工厂可以从这样一个配置中创建基本类型和java bean:
<beans>
<bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance"/>
<string name="greeting">hello world</string>
<int name="answer">42</int>
<boolean name="javaisold">true</boolean>
<float name="percentage">10.2</float>
<double name="salary">100000000.32</double>
<char name="java">j</char>
<null name="dusttodust" />
</ beans>

-------------------------------------------------- -------

ObjectFactory of = ObjectFactory.parseXmlFromAbove();
assertEquals(TaskInstance.class, of.getNewObject("task").getClass());
assertEquals("hello world", of.getNewObject("greeting"));
assertEquals(new Integer(42), of.getNewObject("answer"));
assertEquals(Boolean.TRUE, of.getNewObject("javaisold"));
assertEquals(new Float(10.2), of.getNewObject("percentage"));
assertEquals(new Double(100000000.32), of.getNewObject("salary"));
assertEquals(new Character('j'), of.getNewObject("java"));
assertNull(of.getNewObject("dusttodust"));
你也可以配置列表:
<beans>
<list name="numbers">
<string>one</string>
<string>two</string>
<string>three</string>
</ list>
</ beans>
以及map:
<beans>
<map name="numbers">
<entry><key><int>1</int></key><value><string>one</string></value></entry>
<entry><key><int>2</int></key><value><string>two</string></value></entry>
<entry><key><int>3</int></key><value><string>three</string></value></entry>
</ map>
</ beans>
Bean可以使用直接成员注入和通过属性的setter。
<beans>
<bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
<field name="name"><string>do dishes</string></field>
<property name="actorId"><string>theotherguy</string></property>
</ bean>
</ beans>
Bean可以被引用,被引用的对象不必必须是一个bean,也可以是一个字符串、整型或其他任何对象。
<beans>
<bean name="a" class="org.jbpm.A" />
<ref name="b" bean="a" />
</ beans>
Bean可以使用任何构造器构造(构造函数)。
<beans>
<bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
<constructor>
<parameter class="java.lang.String">
<string>do dishes</string>
</ parameter>
<parameter class="java.lang.String">
<string>theotherguy</string>
</ parameter>
</constructor>
</ bean>
</ beans>
…或者在bean上使用工厂方法…
<beans>
<bean name="taskFactory"
class="org.jbpm.UnexistingTaskInstanceFactory"
singleton="true"/>

<bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
<constructor factory="taskFactory" method="createTask" >
<parameter class="java.lang.String">
<string>do dishes</string>
</ parameter>
<parameter class="java.lang.String">
<string>theotherguy</string>
</ parameter>
</constructor>
</ bean>
</ beans>
…或者在类上使用一个静态工厂方法…
<beans>
<bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
<constructor factory-class="org.jbpm.UnexistingTaskInstanceFactory" method="createTask" >
<parameter class="java.lang.String">
<string>do dishes</string>
</ parameter>
<parameter class="java.lang.String">
<string>theotherguy</string>
</ parameter>
</constructor>
</ bean>
</ beans>
每个命名的对象都可以使用属性singleton=“true”标记为单态,这意味着给定的对象工厂为每个请求将总是返回相同的对象。注意,单态不能在不同对象工厂之间共享。
单态特性导致getObject和getNewObject方法间的区别,对象工厂的典型用户将使用getNewObject,这意味着在一个新的对象图被构造之前对象对象工厂首先要清除对象缓存。在构造对象图期间,非单态对象被存储在对象工厂的对象缓存中,允许共享引用一个对象。单态对象缓存不同于普通对象缓存,单态对象缓存不需要清除,而普通对象缓存在每个getNewObject方法被调用起始会被清除。 第7章持久化在很多情况下,Jbpm需要维护跨越长时间的流程的执行,在这里,“长时间”意味着跨越几个处理事务。因为流程执行就像是状态机,在一个处理事务中,我们就是把流程执行状态机从一个状态转到下一个状态,所以持久化的主要目的就是在等待状态存储流程的执行。
一个流程定义可以表现为三种不同形式:XML、Java对象、Jbpm数据库中记录。执行(运行时)信息和日志信息可以表现为两种形式:Java对象和Jbpm数据库中的记录。

图7.1 转换和不同形式有关XML表示流程定义以及流程档案的更多信息,请参考“第16章Jbpm流程定义语言(JPDL)”。
关于怎样部署流程档案到数据库在“第16.1.1节部署流程档案” 中可以找到。
7.1 持久化API
7.1.1 相关配置框架持久化API集成在了配置框架中,通过JbpmContext暴露出了一些便利方法,因此持久化API要像下面这样在JbpmContext块中使用:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{

// Invoke persistence operations here

} finally {
jbpmContext.close();
}
在下文中,我们假设配置中包含如下持久化服务(如示例配置文件src/config.files/jbpm.cfg.xml):
<jbpm-configuration>

<jbpm-context>
<service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />
...
</ jbpm-context>
...
</ jbpm-configuration>
7.1.2 JbpmContext中的便利方法三个普通的持久化操作是:
l 部署流程
l 启动一个流程的执行
l 继续一个执行首先部署一个流程定义。典型的,这可以从图形化流程设计器或部署流程的Ant任务直接完成,但是在这里你会看到怎样通过编程实现:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
ProcessDefinition processDefinition = ...;
jbpmContext.deployProcessDefinition(processDefinition);
} finally {
jbpmContext.close();
}
要创建一个新的流程执行,我们需要指定一个要实例化执行的流程定义,通常的作法是指定一个流程名称,并让Jbpm在数据库中查找这个流程的最新版本:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
String processName = ...;
ProcessInstance processInstance =
jbpmContext.newProcessInstance(processName);
} finally {
jbpmContext.close();
}
要继续一个流程执行,我们需要从数据库中取出这个流程实例、令牌或者任务实例,在这些POJO Jbpm对象上调用一些方法,然后再把对流程实例的更新保存到数据库中。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
long processInstanceId = ...;
ProcessInstance processInstance =
jbpmContext.loadProcessInstance(processInstanceId);
processInstance.signal();
jbpmContext.save(processInstance);
} finally {
jbpmContext.close();
}
注意:如果你在JbpmContext中使用xxxForUpdate方法,则jbpmContext.save不需要再显式的调用,因为在jbpmContext关闭时它会被自动调用。举例来说,假设我们要通知Jbpm一个任务实例已经完成,(注意:任务实例完成能够触发继续执行,所以相联的流程实例必须保存。)一个非常方便的方法是使用loadTaskInstanceForUpdate方法:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
long taskInstanceId = ...;
TaskInstance taskInstance =
jbpmContext.loadTaskInstanceForUpdate(taskInstanceId);
taskInstance.end();
} finally {
jbpmContext.close();
}
正象是后台信息一样,下面部分解释了Jbpm是怎样管理持久化和使用Hibernate的。
JbpmConfiguration维护了一组服务工厂(ServiceFactory),服务工厂象前面内容所说的在jbpm.cfg.xml中配置,并且是lazy(懒)实例化的。当在第一次需要DbpersistenceServiceFactory时它被实例化,然后服务工厂就被在JbpmConfiguration中维护,DbpersistenceServiceFactory管理一个hibernate SessionFactory,而hibernate SessionFactory也是在第一次被请求的时候才创建的。

图7.2 持久化相关类在调用jbpmConfiguration.createJbpmContext()方法期间,只有JbpmContext被创建,这时没有更多的持久化相关实例。JbpmContext管理一个DbPersistenceService,它在被第一次请求的时候实例化。DbPersistenceServece管理hibernate会话(session),hibernate会话在DbPersistenceServece中也是被Lazy(懒)创建的,因此结果是:一个hibernate会话只有在第一个请求持久化的操作被调用时才被打开,而在这之前不会。
7.1.3 高级API用法
DbPersistenceService维护了一个懒实例化的hibernate 会话,所有的数据库存取都是通过这个hibernate会话完成的。所有的查询和更新都是通过Jbpm暴露出的xxxSession类完成的,例如GraphSession、SchedulerSession、LoggingSession等等,这些session类都是提交hibernate查询并且都使用下层相同的hebernate会话。
XxxxSession类也是通过JbpmContext来获取的。
7.2 配置持久化服务
7.2.1 The hibernate session factory
默认情况下,DbpersistenceServiceFactory将使用classpath根下的资源文件hibernate.cfg.xml来创建hibernate会话工厂。注意:hibernate资源配置文件由“jbpm.hibernate.cfg.xml”属性指定,可以在jbpm.cfg.xml中定制。下面是默认配置:
<jbpm-configuration>
...
<! - 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.properties文件、而不是更新hibernate.cfg.xml文件来方便的更新Jbpm指向自己的数据库:hibernate.cfg.xml仅仅需要拷贝过去不需要做任何更改。
7.2.2 The DbPersistenceServiceFactory
DbpersistencrServiceFactory拥有三个配置属性:isTransactionEnabled、sessionFactoryJndiName和dataSourceJndiName。要指定这几个属性中的任何一个,你需要象bean一样在factory元素中定义服务工厂,如下:
<jbpm-context>
<service name="persistence">
<factory>
<bean factory="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>
l isTransactionEnabled:默认情况下,Jbpm将会开始并且结束hibernate事务。如果禁用事务并且禁止使用hibernate管理事务,可以象上例一样配置isTransactionEnabled属性为false。更多信息,请参考“第7.3节hibernate事务” 。
l sessionFactoryJndiName:默认情况下这个属性为空,意味着会话工厂不从JNDI获取。如果设置了,当需要使用会话工厂创建一个hibernate会话时,则将会从所提供的JNDI名称中通过jndi获取会话工厂。
l dataSourceJndiName:默认情况下这个属性为空,JDBC连接的创建会委托给hibernate。通过指定一个datasource,当打开一个新的会话时,Jbpm将会从datasource中获取一个JDBC连接并且把这个连接提供给hibernate。有关用户提供JDBC连接,请参考“第7.5节用户提供的素材”。
7.3 Hibernate事务默认情况下,Jbpm将委托事务到hibernate,并且使用每个事务一个会话的模式。Jbpm在hibernate会话被打开时启动一个hibernate事务,这在第一次调用jbpmContext的一个持久化操作时发生,事务会在hiberante会话关闭之前被提交,这在jbpmContext.close()中发生。
使用jbpmContext.setRollbackOnly()回滚一个事务,在这种情况下,事务会在jbpmContext.close()方法中关闭会话之前回滚。
要禁止Jbpm在hibernate API之上调用任何事务,可以设置isTransactionEnabled属性为false,就象上面的“第7.2.2 节The DbPersistenceServiceFactory”说明的一样。
7.4 管理事务当在J2EE应用服务器中(如JBOSS)使用Jbpm时,大多情况下需要管理事务。 そのような:
l 在应用服务器中配置一个DataSource
l 配置hibernate使它的连接使用DataSource
l 使用容器管理事务
l 在Jbpm中禁用事务
7.5 用户提供的素材你也可以编程向Jbpm提供JDBC连接、hibernate会话和hibernate会话工厂。
当这些资源提供给Jbpm时,Jbpm会使用所提供的资源,而不是配置中指定的。
JbpmContext类包含了一些方便的方法来实现通过编程注入资源。例如,向Jbpm提供一个JDBC连接,可以使用如下代码:
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
試して{
Connection connection = ...;
jbpmContext.setConnection(connection);

// invoke one or more persistence operations

} finally {
jbpmContext.close();
}
JbpmContext类有如下方便的方法用来支持编程提供资源:
JbpmContext.setConnection(Connection);
JbpmContext.setSession(Session);
JbpmContext.setSessionFactory(SessionFactory);
7.6 自定义查询
Jbpm使用的所有HQL查询都集中在一个配置文件中,这个资源文件在hibernate.cfg.xml配置文件中被引用,如下:
<hibernate-configuration>
...
<!-- hql queries and type defs -->
<mapping resource = "org / jbpm / db / hibernate.queries.hbm.xml" />
...
</ hibernate-configuration>
要自定义一个或更多查询,先拷贝一个原始文件并且把你自定义的版本放在classpath下的某个位置,然后在hibernate.cfg.xml中更新“org/jbpm/db/hibernate.queries.hbm.xml”,使之指向你自己定义的版本。
7.7 数据库兼容
Jbpm可以在hibernate所支持的任何数据库上运行。
Jbpm中的示例配置文件(src/config.files)指定了使用的是hypersonicin in-memory数据库,这个数据库在开发和测试阶段是一个理想的选择,hypersonicin in-memory数据库把数据放在内存中而不是存储到磁盘。
7.7.1 改变Jbpm数据库下面列出了当改变Jbpm使用一个不同数据库时的作法:
l 把jdbc驱动库放在classpath
l 改变Jbpm所使用的hibernate配置
l 在新的数据库中创建表
7.7.2 Jbpm数据库表
Jbpm.db子项目包含了一系列的驱动库、说明和脚本来帮助你在你所选择的数据库上开始工作。请查阅jbpm.dm工程根目录下的readme.html文件来获取更多信息。
尽管Jbpm有能力生成所有数据库的DDL脚本,但是这些不总是最优的,因此你可能想要你的DBA查阅这些生成的DDL,来进行列类型的优化和使用索引。
在开发中,你可能对下面的hibernate配置感兴趣:如果你设置hibernate配置属性“hibernate.hbm2ddl.auto”为“create-drop”(例如在hibernate.cfg.xml中),则在应用中第一次使用时,便会在数据库中自动创建,当应用关闭时,则表会被删除。
也可以编程调用jbpmConfiguration.createSchema()和jbpmConfiguration.dropSchema()方法来实现表的创建和删除。
7.8 结合你自己的hibernate类在你自己的项目中,你可能使用hibernate来持久化,可以使你自己的持久化类与Jbpm持久化类结合,这是可选的。这样做有两个主要的好处:
首先,会话、连接和事务管理变得容易。通过结合Jbpm和你自己的持久化在一个hibernate会话工厂,则只有一个hibernate会话、一个jdbc连接来处理你自己的和Jbpm的持久化,因此,Jbpm的更新与你自己的域模型更新在相同的事务中,这可以排除再使用一个事务管理器。
其次,这毫无争议的就把你自己的hibernate持久化对象融入了流程变量中。
可以通过创建一个核心的hibernate.cfg.xml来很容易的与Jbpm持久化类集成你自己的持久化类,你可以使用Jbpm中的src/config.files/hibernate.cfg.xml作为开始,然后在其中添加你自己的hibernate映射文件的引用。
7.9 定制Jbpm的hibernate映射文件你可以按照如下方式来定制任何Jbpm的hibernate映射文件:
l 从源码(src/java.jbpm/…)或Jbpm库中拷贝Jbpm的hibernate映射文件
l 把拷贝的文件放置到classpath下任何你想要放置的地方
l 在hibernate.cfg.xml配置文件中更新指向自定义的映射文件
7.10 二级缓存流程定义加载一次之后,Jbpm使用hibernate的二级缓存来把它放在内存中,流程定义类和集合在Jbpm的hibernate映射文件中使用cache元素来配置,如下:
<cache usage="nonstrict-read-write"/>
因为流程定义不会改变(应该不会改变),所以把它们放在二级缓存中是很好的做法,请参考“第16.1.3节改变已发布的流程定义”。
二级缓存是JBOSS Jbpm实现的一个很重要的方面,如果没有这个缓存,JBOSS Jbpm在与其它实现BPM引擎的技术进行比较时,会是一个严重的缺陷。
缓存策略设置为nonstrict-read-write。在运行时,缓存策略可以设置为read-only,在这种情况下,你需要一个单独的hibernate映射文件来部署流程,这也是为什么我们选择nonstrict-read-write的原因。

第9章流程建模
9.1 综述流程定义(process definition)基于有向图表示了一个业务流程的规格化描述。图是由节点(node)和转换(transition)组成的,图中每个节点都有一个特定类型,节点的类型定义了运行时的行为。一个流程定义只能有一个开始状态。
令牌(token)是一个执行路线。令牌是运行时概念,它维护了一个指向图中节点的指针。
流程实例是(process instance)流程定义的执行。当一个流程实例创建后,一个令牌也为执行的主要路线创建了,这个令牌被称为流程实例的根令牌(root token),它被定位于流程定义的开始状态。
信号(signal)指示令牌继续图的执行。当令牌接收到一个没有命名的信号,它会经由缺省的离开转换离开它的当前节点;当一个转换名称在信号中被指定时,令牌会经由指定的转换离开节点。发送到流程实例的信号被委托给根令牌。
令牌进入节点后,节点被执行。节点自己有责任让图继续执行,图的继续执行是通过让令牌离开节点完成的。每个节点类型为了图的继续执行可以实现不同的行为,如果一个节点不能传播图的执行,则被表现为一个状态。
动作(Action)是在流程执行中的事件上被执行的java代码片断。在软件需求中,图是信息交流的一个重要手段,但是图只是将要生产的软件的一个视图(影像),它隐藏了很多技术细节。动作是在图的表示之外添加技术细节的一种机制,一旦图被做好,它可以由动作来修饰。主要的事件类型有:进入节点、离开节点、执行转换。
9.2 流程图基本的流程定义是一个由节点和转换组成的图,这些信息在processdefinition.xml中表示。每个节点都有一个类型,如state、decision、fork、join等;每个节点有一组离开转换,可以给离开节点的每个转换一个名称来区分它们。例如:下图显示了jBay拍卖流程的流程图。

图9.1拍卖流程图下面是jBay拍卖流程图的xml表示:
<process-definition>

<開始状態>
<transition to="auction" />
</ start-state>

<state name="auction">
<transition name="auction ends" to="salefork" />
<transition name="cancel" to="end" />
</ state>

<fork name="salefork">
<transition name="shipping" to="send item" />
<transition name="billing" to="receive money" />
</fork>

<state name="send item">
<transition to="receive item" />
</ state>

<state name="receive item">
<transition to="salejoin" />
</ state>

<state name="receive money">
<transition to="send money" />
</ state>

<state name="send money">
<transition to="salejoin" />
</ state>

<join name="salejoin">
<transition to="end" />
</ join>

<end-state name="end" />

</ process-definition>
9.3 节点流程图是由节点和转换组成的,有关图的以及它的扩展模型的更多信息,请参考“第4章面向图的编程”TODO。
每个节点有一个特定类型,节点类型决定了在运行时执行到达节点时将发生什么。Jbpm有一组你可以使用的预定义的节点类型,另外,你也可以编写定制代码来实现你自己指定的节点行为。
9.3.1 节点责任每个节点都有两个主要责任:首先,它可以执行普通java代码,典型情况下,java代码与节点功能是相关的,例如:创建一些任务实例、发送一个通知、更新一个数据库等;其次节点要负责传播流程执行。基本上来说,每个节点在传播流程执行时有以下几个可选方式:
1.不传播执行。这种情况下节点表现为一个等待状态。
2.经由节点的某个离开转换传播执行。这意味着到达本节点的令牌使用API调用executionContext.leaveNode()经由某个离开转换被传递,这时节点作为一个自动节点,它可以执行一些定制的程序逻辑然后自动继续流程执行,而没有等待。
3.创建一个新的执行路径。节点可以决定创建新的令牌,每个新的令牌表示一个新的执行路径,并且每个令牌可以通过节点的离开转换被启动。这种行为的一个很关好的例子就是fork节点。
4.结束执行路径。节点可以决定结束执行路径,这意味着令牌被结束,执行路径也就完结了。
5.更一般的情况,节点可以修改流程实例的整个运行时结构。运行时结构是包含一个令牌树的流程实例,每个令牌表示一个执行路径,节点可以创建和结束令牌,把每个令牌放在图中的节点,并且通过转换启动令牌。

Jbpm像其他任何工作流和BPM引擎一样,包含一组预实现的节点类型,它们有特定的文档配置和行为,但是关于Jbpm和面向图的编程基础(第4章面向图的编程TODO)相对于其他来说其独特之处是对开发者开放模型,开发者可以很容易的编写自己的节点行为,并在流程中使用。
这也就是传统的工作流和BPM系统非常封闭之处,它们通常提供一组固定的节点类型(叫做流程语言),它们的流程语言是封闭的并且执行模型被隐藏在运行环境中。研究工作流模式可以发现,任何流程语言都不足够强大,我们决定做一个简单模型,并且允许开发者编写他们自己的节点类型,而JPDL流程语言则是完全开放的。
接下来我们论述JPDL中非常重要的节点类型。
9.3.2 节点类型task-node
任务节点代表一个或多个被人所执行的任务。因此当执行到达一个任务节点时,任务实例将会在工作流参与者的任务列表中被创建,然后,节点将表现为一个等待状态,当用户执行了他们的任务时,任务的完成会触发恢复执行,换句话说,这将导致一个新的信号在令牌上被调用。
9.3.3 节点类型state(状态)
状态就是一个等待状态,与任务节点不同的是没有任务实例在任务列表中被创建,如果流程需要等待一个外部系统,这是有用的。例如,在节点的入口处(通过node-enter时间的动作),可以发送一个消息到外部系统,然后流程进入等待状态,当外部系统发送一个响应消息时,这可以导致一个token.signal(),用来触发恢复流程执行。
9.3.4 节点类型decision(决策)
实际上有两种方式来建模决策,这两种方式之间的不同是基于“谁”来做决策,可以由流程(请阅读:在流程定义中指定)来做决策,或者由外部实体来提供决策结果。
当由流程来做决策时,就应该使用决策节点了。有两个基本的方法来指定决策标准:简单的方式是在转换上添加条件元素(condition),条件是返回一个布尔值的beanshell脚本表达式,在运行时,决策节点会循环它的离开转换(按照xml中指定的顺序)并计算每个条件,第一个条件结果返回为“true”的转换将被使用。另外一种可选方式是指定一个DecisionHandler的实现,然后决策在java类中被计算并且通过DecisionHandler实现的decide方法返回所选的离开转换。
当决策是由外部部分(意思是:不是流程定义的一部分)来决定时,你可以使用多个转换离开一个状态或等待状态节点,然后,离开转换可以被提供到外

カテゴリ:Default 時間:2018-05-15 人気:1

関連記事

Copyright (C) socapnw.com, All Rights Reserved.

Socapnw All Rights Reserved.

processed in 1.374 (s). 9 q(s)