JBPM リファレンスガイド
JBoss 開発者向け
エディッション 5.2.0
概要
第1章 はじめに
注記
注記
注記
1.1. 概要

図1.1 JPDL コンポーネント概要
1.2. JPDL スイート
- config
- database
- deploy
- designer
- examples
- lib
- src
- JBoss JBPM Web コンソール
- Web アーカイブとしてパッケージ化されます。 プロセスパーティシパントと JBPM 管理者の両者がこのコンソールを使用できます。
- ジョブエクセキュータ
- Console Web Application の一部です。 servlet によって開始され、 タイマーと非同期メッセージを監視し実行するスレッドプールを生成します。
- JBPM テーブル
- デフォルトの Hypersonic データベースに格納されます (既にプロセスが含まれています)。
- サンプルプロセス
- 1 つのサンプルプロセスが既に JBPM データベースへデプロイされています。
- アイデンティティコンポーネント
- アイデンティティコンポーネントライブラリは Web コンソール アプリケーション の一部です。
JBPM_ID_
の接頭辞を持つデータベース内にあるテーブルを所有します。
1.3. JPDL グラフィカルプロセスデザイナー
1.4. JBPM Web コンソールアプリケーション
1.5. JBPM のコアコンポーネント
Enterprise Java Bean
、Web サービスなどすべての Java 環境で使用することができます。
注記
J2EE 1.3
仕様に準拠しているため、すべてのアプリケーションサーバーにデプロイ可能です。
重要
jbpm-jpdl.jar
ファイルの一部は、 Hibernate や Dom4J などのサードパーティーライブラリに依存しています。
1.6. アイデンティティコンポーネント
注記
1.7. JBPM ジョブエグゼキューター
注記
TimerService
が上記の目的で利用される場合もありますが、「標準」環境においてはジョブエグゼキューターが最適です。
jbpm-jpdl
ライブラリにパッケージされています。次に示す 2 つのシナリオのうちいずれかでのみ、このコンポーネントはデプロイ可能です。
JbpmThreadsServlet
が ジョブエグゼキューターを開始するために設定されている場合- 別のJava Virtual Machine が起動されている (そして、そこからジョブエグゼキュータースレッドを実行できる)場合
1.8. まとめ
第2章 チュートリアル
src/java.examples
サブディレクトリにある jBPM ダウンロードパッケージにあります。
注記
注記
2.1. 「Hello World」 サンプル
Hello World
プロセス定義には 3 つのノードがあります (Designer Tool を使わずに簡単なプロセスから始めると、まとまりや組み合わせが理解できるはずです)。
Hello World
プロセスのグラフ表示です。

図2.1 Hello World プロセスグラフ
public void testHelloWorldProcess() { // This method 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'. // The next line parses a piece of xml text into a // ProcessDefinition. A ProcessDefinition is the formal // description of a process represented as a java object. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state>" + " <transition to='s' />" + " </start-state>" + " <state name='s'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>" ); // The next line creates one execution of the process definition. // After construction, the process execution has one main path // of execution (=the root token) that is positioned in the // start-state. ProcessInstance processInstance = new ProcessInstance(processDefinition); // After construction, the process execution has one main path // of execution (=the root token). Token token = processInstance.getRootToken(); // Also after construction, the main path of execution is positioned // in the start-state of the process definition. assertSame(processDefinition.getStartState(), token.getNode()); // Let's start the process execution, leaving the start-state // over its default transition. token.signal(); // The signal method will block until the process execution // enters a wait state. // The process execution will have entered the first wait state // in state 's'. So the main path of execution is now // positioned in state 's' assertSame(processDefinition.getNode("s"), token.getNode()); // Let's send another signal. This will resume execution by // leaving the state 's' over its default transition. token.signal(); // Now the signal method returned because the process instance // has arrived in the end-state. assertSame(processDefinition.getNode("end"), token.getNode()); }
2.2. データベースサンプル
methods
を作成しています。例えば、ある Web アプリケーションのコードがプロセスを開始し、データベースで実行を永続化します。その後、メッセージ駆動型 bean がそのプロセスインスタンスをロードし、実行を再開します。
注記
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 = JbpmConfiguration.parseXmlString( "<jbpm-configuration>" + // A jbpm-context mechanism separates the jbpm core // engine from the services that jbpm uses from // the environment. "<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 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. deployProcessDefinition(); // Suppose we want to start a process instance (=process execution) // when a user submits a form in a web application... 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'. 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. 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 { 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.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. // 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 search for all process instances of this process definition. 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(); } } }
2.3. コンテキストサンプル: プロセス変数
java.util.Map
クラス (こちらは Java オブジェクト) と類似します (プロセス変数はプロセスインスタンスの一部として永続化されます)。
注記
注記
// This example also starts from the hello world process. // This time even without modification. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state>" + " <transition to='s' />" + " </start-state>" + " <state name='s'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>" ); ProcessInstance processInstance = new ProcessInstance(processDefinition); // Fetch the context instance from the process instance // for working with the process variables. ContextInstance contextInstance = processInstance.getContextInstance(); // Before the process has left the start-state, // we are going to set some process variables in the // context of the process instance. contextInstance.setVariable("amount", new Integer(500)); contextInstance.setVariable("reason", "i met my deadline"); // From now on, these variables are associated with the // process instance. The process variables are now accessible // by user code via the API shown here, but also in the actions // and node implementations. The process variables are also // stored into the database as a part of the process instance. processInstance.signal(); // The variables are accessible via the contextInstance. assertEquals(new Integer(500), contextInstance.getVariable("amount")); assertEquals("i met my deadline", contextInstance.getVariable("reason"));
2.4. タスク割り当てのサンプル
AssignmentHandler
の実装を指定し、タスクに対するアクターの算出が含まれるよう使用します。
public void testTaskAssignment() { // The process shown below is based on the hello world process. // The state node is replaced by a task-node. The task-node // is a node in JPDL that represents a wait state and generates // task(s) to be completed before the process can continue to // execute. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition name='the baby process'>" + " <start-state>" + " <transition name='baby cries' to='t' />" + " </start-state>" + " <task-node name='t'>" + " <task name='change nappy'>" + " <assignment" + " class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' />" + " </task>" + " <transition to='end' />" + " </task-node>" + " <end-state name='end' />" + "</process-definition>" ); // Create an execution of the process definition. ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); // Let's start the process execution, leaving the start-state // over its default transition. token.signal(); // The signal method will block until the process execution // enters a wait state. In this case, that is the task-node. assertSame(processDefinition.getNode("t"), token.getNode()); // When execution arrived in the task-node, a task 'change nappy' // was created and the NappyAssignmentHandler was called to determine // to whom the task should be assigned. The NappyAssignmentHandler // returned 'papa'. // In a real environment, the tasks would be fetched from the // database with the methods in the org.jbpm.db.TaskMgmtSession. // Since we don't want to include the persistence complexity in // this example, we just take the first task-instance of this // process instance (we know there is only one in this test // scenario). TaskInstance taskInstance = (TaskInstance) processInstance .getTaskMgmtInstance() .getTaskInstances() .iterator().next(); // Now, we check if the taskInstance was actually assigned to 'papa'. assertEquals("papa", taskInstance.getActorId() ); // Now we suppose that 'papa' has done his duties and mark the task // as done. taskInstance.end(); // Since this was the last (only) task to do, the completion of this // task triggered the continuation of the process instance execution. assertSame(processDefinition.getNode("end"), token.getNode()); }
2.5. カスタムアクションのサンプル
MyActionHandler
を見てください。 MyActionHandler
は ブール型変数 isExecuted
を true
に設定するだけです。この変数は静的であるため、アクションハンドラー (およびアクション自体) からアクセスし、値を検証することができます。
注記
// MyActionHandler represents a class that could execute // some user code during the execution of a jBPM process. public class MyActionHandler implements ActionHandler { // Before each test (in the setUp), the isExecuted member // will be set to false. public static boolean isExecuted = false; // The action will set the isExecuted to true so the // unit test will be able to show when the action // is being executed. public void execute(ExecutionContext executionContext) { isExecuted = true; } }
重要
MyActionHandler.isExecuted
を false
に設定します。
// Each test will start with setting the static isExecuted // member of MyActionHandler to false. public void setUp() { MyActionHandler.isExecuted = false; }
public void testTransitionAction() { // The next process is a variant of the hello world process. // We have added an action on the transition from state 's' // to the end-state. The purpose of this test is to show // how easy it is to integrate Java code in a jBPM process. ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state>" + " <transition to='s' />" + " </start-state>" + " <state name='s'>" + " <transition to='end'>" + " <action class='org.jbpm.tutorial.action.MyActionHandler' />" + " </transition>" + " </state>" + " <end-state name='end' />" + "</process-definition>" ); // Let's start a new execution for the process definition. ProcessInstance processInstance = new ProcessInstance(processDefinition); // The next signal will cause the execution to leave the start // state and enter the state 's' processInstance.signal(); // Here we show that MyActionHandler was not yet executed. assertFalse(MyActionHandler.isExecuted); // ... and that the main path of execution is positioned in // the state 's' assertSame(processDefinition.getNode("s"), processInstance.getRootToken().getNode()); // The next signal will trigger the execution of the root // token. The token will take the transition with the // action and the action will be executed during the // call to the signal method. processInstance.signal(); // Here we can see that MyActionHandler was executed during // the call to the signal method. assertTrue(MyActionHandler.isExecuted); }
enter-node
および leave-node
イベント両方に置かれた同じアクションを示しています。
注記
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state>" + " <transition to='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>" + " <transition to='end'/>" + " </state>" + " <end-state name='end' />" + "</process-definition>" ); ProcessInstance processInstance = new ProcessInstance(processDefinition); assertFalse(MyActionHandler.isExecuted); // The next signal will cause the execution to leave the start // state and enter the state 's'. So the state 's' is entered // and hence the action is executed. processInstance.signal(); assertTrue(MyActionHandler.isExecuted); // Let's reset the MyActionHandler.isExecuted MyActionHandler.isExecuted = false; // The next signal will trigger execution to leave the // state 's'. So the action will be executed again. processInstance.signal(); // Voila. assertTrue(MyActionHandler.isExecuted);
第3章 設定
jbpm.cfg.xml
設定ファイルを指定することです。このファイルがリソースとして存在しない場合は、JBPM ライブラリに含まれるデフォルトの最小設定が使用されます (org/jbpm/default.jbpm.cfg.xml
)。
org.jbpm.JbpmConfiguration
によって表されています。singleton
インスタンスメソッド (JbpmConfiguration.getInstance()
) を利用して取得します。
注記
JbpmConfiguration.parseXxxx
メソッドを使います。
static JbpmConfinguration jbpmConfiguration = JbpmConfinguration.parseResource("my.jbpm.cfg.xml");
JbpmConfiguration
は「スレッドセーフ」であるため、 静的メンバーに保存できます。
JbpmConfiguration
を JbpmContext
オブジェクトの ファクトリ として利用できます。 JbpmContext
は通常 1 つのトランザクションを表します。 次のようにコンテキストブロック内でサービスを使用できるようにします。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { // This is what we call a context block. // Here you can perform workflow operations } finally { jbpmContext.close(); }
JbpmContext
は サービスと構成設定の両方を JBPM が使用できるようにします。
jbpm.cfg.xml
ファイルの値によって設定されます。前述の環境にあるサービスを使用して JBPM がすべての Java 環境で稼働できるようにします。
JbpmContext
のデフォルト設定になります。
<jbpm-configuration> <jbpm-context> <service name='persistence' 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' /> <service name='authentication' factory= 'org.jbpm.security.authentication.DefaultAuthenticationServiceFactory' /> </jbpm-context> <!-- 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' /> --> <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' /> <string name='resource.mail.templates' value='jbpm.mail.templates.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' /> <string name='jbpm.mail.smtp.host' value='localhost' /> <bean name='jbpm.mail.address.resolver' class='org.jbpm.identity.mail.IdentityAddressResolver' singleton='true' /> <string name='jbpm.mail.from.address' value='jbpm@noreply' /> <bean name='jbpm.job.executor' class='org.jbpm.job.executor.JobExecutor'> <field name='jbpmConfiguration'><ref bean='jbpmConfiguration' /> </field> <field name='name'><string value='JbpmJobExecutor' /></field> <field name='nbrOfThreads'><int value='1' /></field> <field name='idleInterval'><int value='60000' /></field> <field name='retryInterval'><int value='4000' /></field> <!-- 1 hour --> <field name='maxIdleInterval'><int value='3600000' /></field> <field name='historyMaxSize'><int value='20' /></field> <!-- 10 minutes --> <field name='maxLockTime'><int value='600000' /></field> <!-- 1 minute --> <field name='lockMonitorInterval'><int value='60000' /></field> <!-- 5 seconds --> <field name='lockBufferTime'><int value='5000' /></field> </bean> </jbpm-configuration>
JbpmContext
設定するサービス実装のセット (特定のサービス実装について取り上げている章に可能な設定オプションの詳細が記載されています)。- 設定リソースへの参照にリンクするすべてのマッピング。設定ファイルの 1 つをカスタマイズしたい場合はこれらのマッピングを更新します。カスタマイズする時は、最初に必ずデフォルトの設定ファイル (
jbpm-3.x.jar
) をクラスパス上の別の場所にバックアップします。その後、JBPM が使用するカスタマイズされたバージョンを示してこのファイルへの参照を更新します。 - JBPM が使用するその他の設定 (特定の内容について取り上げている章に説明があります)。
JbpmContext
には、ほとんどの共通プロセス操作に対する便利なメソッドが含まれています。このサンプルでは、これらのメソッドの使用方法について説明しています。
public void deployProcessDefinition(ProcessDefinition processDefinition) public List getTaskList() public List getTaskList(String actorId) public List getGroupTaskList(List actorIds) public TaskInstance loadTaskInstance(long taskInstanceId) public TaskInstance loadTaskInstanceForUpdate(long taskInstanceId) public Token loadToken(long tokenId) public Token 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(Token token) public void save(TaskInstance taskInstance) public void setRollbackOnly()
注記
XxxForUpdate
メソッドは、ロードされたオブジェクトを「自動保存」登録されるように設計されているため、save
メソッドを手動で呼び出す必要はありません。
jbpm-context
を指定することは可能ですが、その際に各 jbpm-context
に固有の name属性を付けなければなりません (JbpmConfiguration.createContext(String name);
を使用して名前付けされたコンテキストを読み出します)。
JbpmContext.getServices().getService(String name)
による要求があった場合のみ、このサービスが作成されます。
注記
factories
を属性でなく要素 として指定することもできます。 一部の設定情報をファクトリオブジェクトに注入する際に要素の指定が必要となります。
注記
object factory
と呼ばれます。
3.1. ファクトリのカスタマイズ
警告
StateObjectStateException
をログに記録し、これに対するスタックトレース
を生成します。スタックトレースを削除するには、org.hibernate.event.def.AbstractFlushingEventListener
を FATAL
に設定します。
<service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />
注記
log4j.logger.org.hibernate.event.def.AbstractFlushingEventListener=FATAL
重要
<service name="persistence"> <factory> <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory"> <field name="dataSourceJndiName"> <string value="java:/myDataSource"/> </field> <field name="isCurrentSessionEnabled"><true /></field> <field name="isTransactionEnabled"><false /></field> </bean> </factory> </service>
3.2. 設定プロパティ
- jbpm.byte.block.size
- 添付ファイルとバイナリ変数は、固定サイズのバイナリオブジェクトのリストとしてデータベースに保存されます (これは異なるデータベース間の移植性を向上するのが目的で、JBPM の組み込みも簡易化されます)。このパラメーターは、固定長チャンクのサイズを制御します。
- jbpm.task.instance.factory
- タスクインスタンスが作成される方法をカスタマイズするには、このプロパティで完全修飾クラス名を指定します。(通常、この操作は
TaskInstance
bean をカスタマイズし、新しいプロパティを追加する時に必要になります)。指定したクラス名がorg.jbpm.taskmgmt.TaskInstanceFactory
インターフェースを実装するようにしなければなりません (詳細は、「タスクインスタンスのカスタマイズ」 を参照してください)。 - jbpm.variable.resolver
- これを使い、JBPM が JSF に類似した表現にある最初の用語を検索する方法をカスタマイズします。
3.3. その他の設定ファイル
hibernate.cfg.xml
- このファイルには、 Hibernate マッピングリソースファイルへの参照と設定の詳細が含まれます。別のファイルを指定するには、
jbpm.properties
の jbpm.hibernate.cfg.xml プロパティを設定します (デフォルトの Hibernate 設定ファイルはsrc/config.files/hibernate.cfg.xml
サブディレクトリにあります)。 org/jbpm/db/hibernate.queries.hbm.xml
- このファイルには、JBPM セッション (
org.jbpm.db.*Session
) で使用される Hibernate クエリが含まれています。 org/jbpm/graph/node/node.types.xml
- このファイルは、 XML ノードエレメントを
Node
実装クラスにマップするために使用されます。 org/jbpm/graph/action/action.types.xml
- このファイルは、 XML アクションエレメントを
Action
実装クラスへマップするために使用されます。 org/jbpm/calendar/jbpm.business.calendar.properties
- 「営業時間」と「自由時間」の定義が含まれます。
org/jbpm/context/exe/jbpm.varmapping.xml
- JBPM データベースに保存するため、プロセス変数の値 (Javaオブジェクト) をどのように変数インスタンスに変換するか指定します。
org/jbpm/db/hibernate/jbpm.converter.properties
id-to-classname
マッピングを指定します。 id はデータベースに保存されます。org.jbpm.db.hibernate.ConverterEnumType
は、 識別子をsingleton
オブジェクトにマップするため使用されます。org/jbpm/graph/def/jbpm.default.modules.properties
- デフォルトで新しい
ProcessDefinition
に追加されるモジュールを指定します。 org/jbpm/jpdl/par/jbpm.parsers.xml
- プロセスアーカイブ解析のフェーズを指定します。
3.4. 楽観的同時実行制御のロギング
org.hibernate.StateObjectStateException
例外が発生する場合があります。
optimistic locking failed
StateObjectStateException
をログに記録することもできます。スタックトレースを削除するには、org.hibernate.event.def.AbstractFlushingEventListener
クラスを FATAL
に設定します。次の設定を使用して log4j でこの操作を行います。
log4j.logger.org.hibernate.event.def.AbstractFlushingEventListener=FATAL
jbpm.cfg.xml
に追加します。
<boolean name="jbpm.hide.stale.object.exceptions" value="false" />
3.5. オブジェクトファクトリ
<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>
<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>
setter
メソッドを使用して Bean を設定します。このコードはその方法を示しています。
<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>
<beans> <bean name="a" class="org.jbpm.A" /> <ref name="b" bean="a" /> </beans>
<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>
static factory
メソッドを使用して 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>
static factory
メソッドを使用して Bean を構築することができます。
<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"
を使用して各名前付きのオブジェクトを singleton
としてマークします。これにより、各要求に対して object factory
が常に同じオブジェクトを返すようにします。
注記
Singletons
を異なるオブジェクトファクトリで共有することはできません。
注記
singleton
機能により、getObject
というメソッドと getNewObject
というメソッドを区別することができます。新しいオブジェクトグラフが構築される前に object factory
のオブジェクトキャッシュを消去するため、通常は getNewObject
を使用します。
object factory
のキャッシュに保存されます。 これにより、 1 つのオブジェクトへの参照を共有できるようになります。 singleton object cache
は plain object cache
とは異なります。 singleton
キャッシュは消去されることがありませんが、 plain object cache
メソッドが開始される度に plain object cache
は消去されます。
第4章 永続性
注記
注記
4.1. 永続性アプリケーションプログラミングインターフェース
4.1.1. 設定フレームワークとの関係
JbpmContext
にある convenience persistence
メソッドの一部を公開し、JBPM context block
が永続 API 操作を呼び出せるようにします。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { // Invoke persistence operations here } finally { jbpmContext.close(); }
4.1.2. JbpmContext の便利なメソッド
- プロセスのデプロイ
- 新規プロセスの実行開始
- プロセス実行の継続
deployprocess
の ant タスクによって直接実行されます。Java から直接実行するには、次のコードを使用します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { ProcessDefinition processDefinition = ...; jbpmContext.deployProcessDefinition(processDefinition); } finally { jbpmContext.close(); }
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { String processName = ...; ProcessInstance processInstance = jbpmContext.newProcessInstance(processName); } finally { jbpmContext.close(); }
taskInstance
のいずれかをデータベースより取得し、JBPM POJO (Plain Old Java Object) 上でメソッドを呼び出します。その後、processInstance
への更新をデータベースに保存します。
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { long processInstanceId = ...; ProcessInstance processInstance = jbpmContext.loadProcessInstance(processInstanceId); processInstance.signal(); jbpmContext.save(processInstance); } finally { jbpmContext.close(); }
注記
JbpmContext
クラスで ForUpdate
メソッドが使用される場合、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(); }
重要
JbpmConfiguration
は ServiceFactories
のセットを維持します。ServiceFactories
は jbpm.cfg.xml
ファイルを使い設定され、必要な時にインスタンス化されます。
DbPersistenceServiceFactory
は最初に必要となった時のみインスタンス化されます。 その後、 ServiceFactory
は JbpmConfiguration
で維持されます。
DbPersistenceServiceFactory
は Hibernate の ServiceFactory
を管理しますが、 最初に要求があった時のみインスタンス化されます。
注記
jbpmConfiguration.createJbpmContext()
クラスが呼び出されると、JbpmContext
のみが作成されます。この時点では永続性に関連する初期化はこれ以上発生しません。JbpmContext
は、最初に要求があった時にインスタンス化される DbPersistenceService
を管理します。DbPersistenceService
クラスは、最初に必要になった時のみインスタンス化される Hibernate を管理します (永続性を必要とする最初の操作が呼び出された時のみ Hibernate セッションが開きます)。

図4.1 永続性に関連するクラス
4.2. 永続サービスの設定
4.2.1. データベース互換性
src/config.files
は、開発やテストに最適な H2 インメモリデータベースの使用を指定します (H2 はメモリ内のすべてのデータを保持し、ディスク上には何も保存しません)。
4.2.1.1. JDBC 接続の分離レベル
READ_COMMITTED
に設定してください。
警告
READ_UNCOMMITTED
(分離レベル 0、H2 によってサポートされる唯一の分離レベル) に設定すると、job executor
で競合状態が発生することがあります。また、複数のトークンが同期化されると競合状態が発生することもあります。
4.2.1.2. データベースの変更
- JDBC ドライバーライブラリアーカイブをクラスパスに置きます。
- JBPM が使用する Hibernate 設定を更新します。
- 新しいデータベースにスキーマを作成します。
4.2.1.3. データベーススキーマ
jbpm.db
サブプロジェクトにはドライバー、説明、スクリプトが含まれています。 詳細は、jbpm.db
プロジェクトの root にある readme.html
を参照してください。
注記
create-drop
に設定すると、 データベースがアプリケーションで初めて使用されるとスキーマが自動的に作成されます。 アプリケーションが終了すると、 スキーマはドロップされます。
4.2.1.3.1. プログラムでデータベーススキーマ操作
org.jbpm.JbpmConfiguration
のcreateSchema
とdropSchema
メソッドを使いデータベーススキーマを作成、削除するためのAPIを提供します。設定済みのデータベースユーザーが持つ権限以外に、これらのメソッドの呼び出しへの制限はありません。
重要
注記
org.jbpm.db.JbpmSchema
クラスが提供する幅広い機能の一部となっています。
4.2.1.4. Hibernate クラスとの統合
hibernate.cfg.xml
ファイルを 1 つ作成します。デフォルトの JBPM hibernate.cfg.xml
を使用し、独自の Hibernate マッピングファイルへの参照を追加してカスタマイズするのが最も簡単な方法でしょう。
第5章 Java EE アプリケーションサーバー機能
5.1. エンタープライズ Bean
CommandServiceBean
は、別の JBPM コンテキスト内でexecute
メソッドを呼び出すことによって JBoss Business Process Manager を実行するステートレスセッション Bean です。
表5.1 コマンドサービス Bean 環境
名前 | 種類 | 説明 |
---|---|---|
JbpmCfgResource | 環境エントリ | JBPM 設定を読み取るクラスパスリソース。オプションで、デフォルトは jbpm.cfg.xml です。 |
ejb/TimerEntityBean | EJB 参照 | スケジューラサービスを実装するローカルエンティティ Bean へのリンク。 タイマーを含むプロセスに必要です。 |
jdbc/JbpmDataSource | リソースマネージャ参照 | JDBC 接続を JBPM 永続サービスに提供するデータソースの論理名です。Hibernate 設定ファイルの hibernate.connection.datasource プロパティに一致する必要があります。 |
jms/JbpmConnectionFactory | リソースマネージャ参照 | JMS 接続を JBPM メッセージサービスに提供するファクトリの論理名です。非同期続行を含むプロセスに必要です。 |
jms/JobQueue | メッセージ送信先参照 | JBPM メッセージサービスはこのキューにジョブメッセージを送信します。ジョブリスナー Bean がメッセージを受信するキューと同じキューになるように、message-destination-link が一般的な論理送信先 JobQueue を示します。 |
jms/CommandQueue | メッセージ送信先参照 | コマンドリスナー Bean はこのキューからメッセージを受信します。 コマンドメッセージを送信するキューと同じキューになるように、 message-destination-link element は一般的な論理送信先 CommandQueue を参照します。 |
CommandListenerBean
はコマンドメッセージを CommandQueue
でリッスンするメッセージ駆動型 Bean です。この Bean はコマンド実行を CommandServiceBean
に委譲します。
org.jbpm.Command
インタフェースを実装できる Java オブジェクトである必要があります (メッセージプロパティがある場合は無視されます)。メッセージが必要とされる書式でない場合、メッセージは DeadLetterQueue
へ転送され、それ以降の処理は行われません。送信先参照が存在しない場合、メッセージは拒否されます。
replyTo
返信先を指定している場合、 コマンド実行の結果は object message
にラッピングされ、 その返信先に送信されます。
command connection factory environment reference
は、 Java メッセージサービス接続を提供するために使用されるリソースマネージャを示します。
JobListenerBean
は、 asynchronous continuations をサポートするために JbpmJobQueue
でジョブメッセージをリッスンするメッセージ駆動型 Bean です。
注記
long
の jobId と呼ばれるプロパティがなければなりません。 このプロパティは、 データベースで待機中の Job への参照が含まれていなければなりません。 メッセージ本体が存在する場合は無視されます。
CommandListenerBean
を拡張し、 後の環境エントリとカスタム化に利用可能なリソース参照を継承します。
表5.2 コマンド/ジョブリスナー Bean 環境
名前 | 種類 | 説明 |
---|---|---|
ejb/LocalCommandServiceBean | EJB 参照 | 別の JBPM コンテキストでコマンドを実行するローカルセッション Bean へのリンクです。 |
jms/JbpmConnectionFactory | リソースマネージャ参照 | 結果メッセージを生成するために Java メッセージサービスの接続を提供するファクトリの論理名です。 返信先を指定するコマンドメッセージに必要です。 |
jms/DeadLetterQueue | メッセージ送信先参照 | コマンドを含まないメッセージは、 ここで参照されるキューに送信されます。 省略可能であり、 使用しない場合はこのようなメッセージは拒否され、 コンテナが再配信することがあります。 |
TimerEntityBean
は、 スケジューリングのため Enterprise Java Bean タイマサービスによって使用されます。 有効期限が切れると、 タイマーの実行は command service
Bean に委譲されます。
TimerEntityBean
は、 ビジネスプロセスマネージャのデータソースにアクセスする必要があります。 Enterprise Java Bean デプロイメント記述子は、 エンティティ Bean をデータベースにマップする方法を定義しません (コンテナプロバイダによって定義されます)。 JBoss Application Server では、 jbosscmp-jdbc.xml 記述子がデータソースの JNDI 名とリレーショナルマッピングデータ (テーブルや列名など) を定義します。
注記
java:comp/env/jdbc/JbpmDataSource
) ではなくグローバル JNDI 名 (java:JbpmDS
) を使用します。
注記
TimerServiceBean
という名前のステートレスセッション Bean を使用しました。 このセッション方式は、 cancellation
メソッドに回避できないボトルネックが発生する原因となっていたため廃止しなければなりませんでした。 セッション Bean に ID がないため、 タイマーサービスはすべてのタイマーを反復してキャンセルするタイマを見つけなければなりませんでした。
TimerEntityBean
と同じ環境で動作するため、移行も簡単です。
表5.3 タイマーエンティティ / サービス Bean 環境
名前 | 種類 | 説明 |
---|---|---|
ejb/LocalCommandServiceBean | EJB 参照 | 別の JBPM コンテキストでタイマーを実行するローカルのセッション Bean へのリンクです。 |
5.2. JBPM エンタープライズ設定
jbpm.cfg.xml
に含まれています。
<jbpm-context> <service name="persistence" factory="org.jbpm.persistence.jta.JtaDbPersistenceServiceFactory" /> <service name="message" factory="org.jbpm.msg.jms.JmsMessageServiceFactory" /> <service name="scheduler" factory="org.jbpm.scheduler.ejbtimer.EntitySchedulerServiceFactory" /> </jbpm-context>
JtaDbPersistenceServiceFactory
は、Business Process Manager がJTAトランザクションに参加できるようにします。既存のトランザクションがある場合は、JTAの永続サービスがそのトランザクションに「紐付け」されますが、そうでない場合は新規トランザクションが開始されます。Business Process Manager のエンタープライズ bean はトランザクション管理をコンテナに委譲するよう設定されます。ただし、(Web アプリケーションなど) 有効なトランザクションがない環境においてJbpmContext を作成する場合、新規トランザクションが自動的に開始されます。JTA persistence service factory
には、下記の設定可能なフィールドが含まれます。
- isCurrentSessionEnabled
- これが
true
に設定されている場合、Business Process Manager は、作動中のJTAトランザクションに関連付いた現在のHibernate セッションを使います。これはデフォルト設定です (詳細は http://www.hibernate.org/hib_docs/v3/reference/en/html/architecture.html#architecture-current-session を参照してください)。コンテキストセッションの仕組みを活用しアプリケーションの別の箇所で JBPMと同じセッションを使います。これはSessionFactory.getCurrentSession()
への呼び出しを使うことで実行します。または、isCurrentSessionEnabled をfalse
に設定し、JbpmContext.setSession(session)
メソッドを使い当セッションを投入することで、JBPM へ Hibernate セッションを提供します。これにより、JBPM が同アプリケーションの他の部分と同じHibernate セッションを使うようにします。注記
Hibernate セッションは (永続コンテキストなどを使い) ステートレスセッション bean に注入可能です。 - isTransactionEnabled
- これが
true
に設定されると、JBPMはJbpmConfiguration.createJbpmContext()
メソッドを使いコミットさせることで、Hibernateのtransaction API
からトランザクションを開始します(JbpmContext.close()
が呼び出されると Hibernate セッションは終了します)。警告
Business Process Manager がEARとしてデプロイされている、つまりisTransactionEnabledがデフォルトでfalse
に設定されている場合、これは望ましい動作ではありません(詳細はhttp://www.hibernate.org/hib_docs/v3/reference/en/html/transactions.html#transactions-demarcation を参照してください)。
JmsMessageServiceFactory
は、Java Message Service インターフェースで公開された信頼性のある通信インフラストラクチャーを活用することで、asynchronous continuation messages
をJobListenerBean
に配信します。JmsMessageServiceFactory
は以下の設定可能なフィールドを公開します。
- connectionFactoryJndiName
- JNDIの初期コンテキストでのJMS 接続ファクトリ名で、デフォルトは
java:comp/env/jms/JbpmConnectionFactory
となっています。 - destinationJndiName
- ジョブメッセージが送信されるJMSの宛て先名で、
JobListenerBean
のメッセージ受信元と一致します。デフォルトはjava:comp/env/jms/JobQueue
となっています。 - isCommitEnabled
- Business Process Manager がJava Message Service セッションを
JbpmContext.close()
時にコミットすべきか指定します。JMSメッセージサービスが作成するメッセージは、現在のトランザクションがコミットする前に受信されるべきではありません。そのため、このサービスが作成したセッションは常に処理されます。デフォルト値はfalse
ですが、JTAトランザクション全体でJava Message Service セッションが制御されているため、使用中のconnection factory
がXA対応である場合に適しています。反対に、JMS接続ファクトリがXA対応でない場合、このフィールドをtrue
に設定し、Business Process Manager がJMSセッションのローカルトランザクションを明示的にコミットするようにしてください。
EntitySchedulerServiceFactory
を使いビジネスプロセスタイマーをスケジュールします。Enterprise Java Bean コンテナ提供の予定イベントに対してトランザクション通知サービス上に構築することで行います。EJBscheduler service factory
には、以下のような設定可能なフィールドがあります。
- timerEntityHomeJndiName
- JNDI初期コンテキストにおける
TimerEntityBean
のローカルホームインターフェース名で、デフォルト値はjava:comp/env/ejb/TimerEntityBean
となっています。
5.3. Hibernate エンタープライズ設定
hibernate.cfg.xml
ファイルには以下の設定アイテムが含まれます。これらを変更し、他のデータベースやアプリケーションサービスをサポートします。
<!-- sql dialect --> <property name="hibernate.dialect"> org.hibernate.dialect.HSQLDialect </property> <property name="hibernate.cache.provider_class"> org.hibernate.cache.HashtableCacheProvider </property> <!-- DataSource properties (begin) --> <property name="hibernate.connection.datasource"> java:comp/env/jdbc/JbpmDataSource </property> <!-- DataSource properties (end) --> <!-- 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> <!-- JTA transaction properties (end) --> <!-- CMT transaction properties (begin) === <property name="hibernate.transaction.factory_class"> org.hibernate.transaction.CMTTransactionFactory </property> <property name="hibernate.transaction.manager_lookup_class"> org.hibernate.transaction.JBossTransactionManagerLookup </property> ==== CMT transaction properties (end) -->
hibernate.dialect
設定をお使いのデータベース管理システムに適したものに置き換えます (詳細はhttp://www.hibernate.org/hib_docs/v3/reference/en/html/session-configuration.html#configuration-optional-dialectsを参照してください)。
HashtableCacheProvider
は、他の対応キャッシュプロバイダーで置き換えることが可能です (詳細は http://www.hibernate.org/hib_docs/v3/reference/en/html/performance.html#performance-cache を参照してください)。
JTATransactionFactory
を使うよう設定されています。既存のトランザクションがある場合、JTAトランザクションファクトリはこれを使いますが、ない場合は新規トランザクションを作成します。JBPM エンタープライズ bean はコンテナーへトランザクション管理を委譲するよう設定されています。ただし、(Web アプリケーションなど) アクティブなトランザクションがないコンテキストで JBPM API が使われている場合、自動で起動します。
CMTTransactionFactory
へ切り替えます。この設定により、Hibernate は常に既存のトランザクションを検索し、何も見つからなかった場合は問題を報告します。
5.4. クライアントのコンポーネント
<session> <ejb-name>MyClientBean</ejb-name> <home>org.example.RemoteClientHome</home> <remote>org.example.RemoteClient</remote> <local-home>org.example.LocalClientHome</local-home> <local>org.example.LocalClient</local> <ejb-class>org.example.ClientBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <ejb-local-ref> <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>org.jbpm.ejb.LocalTimerEntityHome</local-home> <local>org.jbpm.ejb.LocalTimerEntity</local> </ejb-local-ref> <resource-ref> <res-ref-name>jdbc/JbpmDataSource</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref> <res-ref-name>jms/JbpmConnectionFactory</res-ref-name> <res-type>javax.jms.ConnnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> <message-destination-ref> <message-destination-ref-name> jms/JobQueue </message-destination-ref-name> <message-destination-type>javax.jms.Queue</message-destination-type> <message-destination-usage>Produces</message-destination-usage> </message-destination-ref> </session>
<session> <ejb-name>MyClientBean</ejb-name> <jndi-name>ejb/MyClientBean</jndi-name> <local-jndi-name>java:ejb/MyClientBean</local-jndi-name> <ejb-local-ref> <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name> <local-jndi-name>java:ejb/TimerEntityBean</local-jndi-name> </ejb-local-ref> <resource-ref> <res-ref-name>jdbc/JbpmDataSource</res-ref-name> <jndi-name>java:JbpmDS</jndi-name> </resource-ref> <resource-ref> <res-ref-name>jms/JbpmConnectionFactory</res-ref-name> <jndi-name>java:JmsXA</jndi-name> </resource-ref> <message-destination-ref> <message-destination-ref-name> jms/JobQueue </message-destination-ref-name> <jndi-name>queue/JbpmJobQueue</jndi-name> </message-destination-ref> </session>
<web-app> <servlet> <servlet-name>MyClientServlet</servlet-name> <servlet-class>org.example.ClientServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyClientServlet</servlet-name> <url-pattern>/client/servlet</url-pattern> </servlet-mapping> <ejb-local-ref> <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>org.jbpm.ejb.LocalTimerEntityHome</local-home> <local>org.jbpm.ejb.LocalTimerEntity</local> <ejb-link>TimerEntityBean</ejb-link> </ejb-local-ref> <resource-ref> <res-ref-name>jdbc/JbpmDataSource</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref> <res-ref-name>jms/JbpmConnectionFactory</res-ref-name> <res-type>javax.jms.ConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> <message-destination-ref> <message-destination-ref-name> jms/JobQueue </message-destination-ref-name> <message-destination-type>javax.jms.Queue</message-destination-type> <message-destination-usage>Produces</message-destination-usage> <message-destination-link>JobQueue</message-destination-link> </message-destination-ref> </web-app>
<jboss-web> <ejb-local-ref> <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name> <local-jndi-name>java:ejb/TimerEntityBean</local-jndi-name> </ejb-local-ref> <resource-ref> <res-ref-name>jdbc/JbpmDataSource</res-ref-name> <jndi-name>java:JbpmDS</jndi-name> </resource-ref> <resource-ref> <res-ref-name>jms/JbpmConnectionFactory</res-ref-name> <jndi-name>java:JmsXA</jndi-name> </resource-ref> <message-destination-ref> <message-destination-ref-name> jms/JobQueue </message-destination-ref-name> <jndi-name>queue/JbpmJobQueue</jndi-name> </message-destination-ref> </jboss-web>
5.5. まとめ
第6章 プロセスのモデリング
6.1. 便利な定義
entering a node
、 leaving a node
、 taking a transition
です。
6.2. プロセスグラフ
processdefinition.xml
という名前の XML ファイルに格納されます。 各ノードは type (state
、 decision
、 fork
、 join
など) を持たなければなりません。 各ノードは、 退場遷移 のセットを持っています。 明確にするために、 ノードから退場する遷移に名前付けることができます。 下図はオークションプロセスのプロセスグラフを表しています。

図6.1 オークションプロセスグラフ
<process-definition> <start-state> <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>
6.3. ノード
6.3.1. ノードの責任
- 実行を伝播できません (ノードは
wait state
として挙動します)。 - ノードの
leaving transitions
の 1 つで実行を伝播できます (既にノードに入場したトークンが、 API 呼び出しexecutionContext.leaveNode(String)
により、executionContext.leaveNode(String)
の 1 つで渡されることを意味します)。 このノードは、 カスタムプログラミングロジックの一部を実行し、 待機背図にプロセス実行を自動的に継続するため、 ある意味自動的に動作するようになります。 - ノードは、 新しい実行パスを表す新しいトークンの作成を決定できます。 新しい各トークンはノードの
leaving transitions
上で開始されます。 このような動作のよい例がfork node
になります。 - 実行パスを終了できます。 これは、 トークンが終了したことを意味します。
- プロセスインスタンスはランタイム構造全体を変更できます。 ランタイム構造は、 各トークンが実行パスを表すトークンのツリーを含んだプロセスインスタンスです。 ノードは、 トークンの作成や終了を行い、 各トークンをグラフのノードに置いたり、遷 移でトークンを開始することができます。
6.3.2. ノードタイプ: タスクノード
wait state
に入場します。ユーザーがタスクを終えると、 実行がトリガーされ再開されます。
6.3.3. ノードタイプ: 状態
wait state
です。 タスクノードとの違いは、 タスクリスト中ではどのようなタスクインスタンスも作成されないことです。 これは、プロセスが外部システムを待つ場合に役立ちます。 その後で、 プロセスは待機状態に入ります。 外部システムが応答メッセージを送信すると、 通常 token.signal()
が呼び出され、 プロセス実行の再開がトリガーされます。
6.3.4. ノードタイプ - 決定
- 決定はプロセスにより行われ、プロセス定義に指定されます。
- 外部のエンティティが決定します。
decision node
が使用されます。2 つの方法の 1 つを決定基準として指定します。最も簡単な指定方法は、遷移へ condition 要素を追加することです (条件は EL 表現またはブール型変数を返す beanshell スクリプトです)。
leaving transitions
上で最初にループします。これにより、xml で指定された順序でこれらの遷移が評価されます。条件が true
に解決された最初の 遷移が取得されます。条件を持つすべての遷移が false
に解決されると、デフォルトの遷移 (XML で最初の遷移) が取得されます。
leaving transitions
の 1 つへ解決する必要があります。
DecisionHandler
インターフェースの実装を指定できるため、 決定で handler 要素を使用することができます。 この場合、決定は Java クラスで計算され、 選択されたleaving transition
が DecisionHandler
実装の decide
メソッドによって返されます。
state
や wait state
を退場する複数の遷移を常に使用します。 退場遷移は、 wait state
の終了後、 実行処理を再開させる外部トリガーに用意できます (例えば、Token.signal(String transitionName)
や TaskInstance.end(String transitionName)
など)。
6.3.5. ノードタイプ - フォーク
6.3.6. ノードタイプ - ジョイン
leaving transition
へ渡されます。 まだ兄弟トークンがアクティブな場合、 ジョインは wait state
として振る舞います。
6.3.7. ノードタイプ - ノード
actionhandler
に記述されたカスタムコードはどのような処理も行えますが、 実行を渡す責任もあることに注意してください (詳細は 「ノードの責任」 を参照してください)。
6.4. 遷移(transition)
Map getLeavingTransitionsMap()
メソッドは、 List getLeavingTransitions()
より少ない要素を返します)。
6.5. アクション
重要

図6.2 データベース更新のアクション
public class RemoveEmployeeUpdate implements ActionHandler { public void execute(ExecutionContext ctx) throws Exception { // get the fired employee from the process variables. String firedEmployee = (String) ctx.getContextInstance().getVariable("fired employee"); // by taking the same database connection as used for the jbpm // updates, we reuse the jbpm transaction for our database update. Connection connection = ctx.getProcessInstance().getJbpmSession().getSession().getConnection(); Statement statement = connection.createStatement(); statement.execute("DELETE FROM EMPLOYEE WHERE ..."); statement.execute(); statement.close(); } }
<process-definition name="yearly evaluation"> <state name="fire employee"> <transition to="collect badge"> <action class="com.nomercy.hr.RemoveEmployeeUpdate" /> </transition> </state> <state name="collect badge"> </process-definition>
注記
6.5.1. アクション参照
6.5.2. イベント
node-enter
イベントと node-leave
イベントの両方を発生することができます (イベントはアクションの「フック」です。各イベントはアクションの一覧を持っています。JBPM エンジンがイベントを開始すると、アクションの一覧が実行されます)。
6.5.3. イベントを渡す
6.5.4. スクリプト
- executionContext
- token
- node
- task
- taskInstance
<process-definition> <event type="node-enter"> <script> System.out.println("this script is entering node "+node); </script> </event> ... </process-definition>
<process-definition> <event type="process-end"> <script> <expression> a = b + c; </expression> <variable name='XXX' access='write' mapped-name='a' /> <variable name='YYY' access='read' mapped-name='b' /> <variable name='ZZZ' access='read' mapped-name='c' /> </script> </event> ... </process-definition>
YYY
と ZZZ
は、 それぞれスクリプト変数 b
と c
として、 スクリプトで使用できるようになります。 スクリプトが終了後、 スクリプト変数 a
の値は、 プロセス変数 XXX
に保存されます。
read
が含まれる場合、 スクリプト評価の前にプロセス変数はスクリプト変数として読み込まれます。 access属性にwrite
が含まれる場合、 スクリプト評価の後にプロセス変数はスクリプト変数として保存されます。 mapped-name 属性は、スクリプト中で別名でプロセス変数を使用可能にします。 プロセス変数の名前に空白文字や無効な文字が含まれている場合にこの属性を使用します。
6.5.5. カスタムイベント
GraphElement.fireEvent(String eventType, ExecutionContext executionContext);
メソッドを呼び出します。 イベントタイプの名前は自由に選択できます。
6.6. Super-States
6.6.1. Super-state 遷移
6.6.2. Super-state イベント
superstate-enter
と superstate-leave
の 2 つがあります。これらのイベントはノードが入退場した遷移に関係なく発生します (super-state 内でトークンが遷移する限り、イベントは発生しません)。
注記
6.6.3. 階層名
/
) で分けた名前を指定しなければなりません (スラッシュはノード名を分けます。上位レベルを参照する場合は、.
を利用します)。次のサンプルは、super-state にあるノードの参照する方法になります。
<process-definition> <state name="preparation"> <transition to="phase one/invite murphy"/> </state> <super-state name="phase one"> <state name="invite murphy"/> </super-state> </process-definition>
<process-definition> <super-state name="phase one"> <state name="preparation"> <transition to="../phase two/invite murphy"/> </state> </super-state> <super-state name="phase two"> <state name="invite murphy"/> </super-state> </process-definition>
6.7. 例外ハンドリング
exception-handler
の一覧を process-definition
、 node
、 transition
で指定することができます。 各例外ハンドラはアクションの一覧を持ちます。 委譲されたクラスで例外が発生すると 、適切な exception-handler
に対してプロセス要素の親階層が検索され、 アクションが実行されます。
重要
token.signal()
を呼び出したクライアントへスローされます。検出された例外については、何も発生しなかったようにグラフ実行が継続されます。
注記
Token.setNode(Node node)
を使用して、 例外ハンドリング action
のグラフ内にある任意のノードにトークンを置きます。
6.8. プロセス構成
process-state
を用いてプロセス構成をサポートします。 別のプロセス定義に関連する状態があります。 グラフ実行が process-state
に入場すると、 サブプロセスの新しいインスタンスが作成されます。 そのサブプロセスはプロセス状態に入場した実行パスに関連付けされます。 親プロセスの実行パスは、 サブプロセスが終了するまで待機し、 サブプロセス終了後にプロセス状態を退場し、 スーパープロセスでグラフ実行を続けます。
<process-definition name="hire"> <start-state> <transition to="initial interview" /> </start-state> <process-state name="initial interview"> <sub-process name="interview" /> <variable name="a" access="read,write" mapped-name="aa" /> <variable name="b" access="read" mapped-name="bb" /> <transition to="..." /> </process-state> ... </process-definition>
hire
プロセスには interview
プロセスを引き起こす process-state
が含まれています。 実行が first interview
に入場すると、 interview
プロセスの新しい実行 (プロセスインスタンス) が作成されます。 バージョンを明示的に指定しないと、 サブプロセスの最新バージョンが使用されます。 ビジネスプロセスマネージャーが特定バージョンのインスタンスを作成するようにするには、 任意の version 属性を指定します。 サブプロセスが実際に作成されるまで指定バージョンまたは最新バージョンのバインディングを延期するには、 任意の binding 属性を late
に設定します。
hire
プロセス変数 a
が interview
プロセス変数 aa
へコピーされます。 同様に、 hire
変数 b
が interview 変数 bb
へコピーされます。 interview プロセスが終了すると、 変数 aa
のみが a
変数にコピーし直されます。
6.9. カスタムノードの動作
ActionHandler
の特別な実装を使用してカスタムノードを作成します。 以下は、 ERP システムより値を読み取り、 プロセス変数より数値を追加し、 結果を ERPシ ステムに保存する例になります。 数値の大きさを基に、 small amounts
遷移または large amounts
遷移を使用して終了します。

図6.3 ERP サンプルを更新するためのプロセススニペット
public class AmountUpdate implements ActionHandler { public void execute(ExecutionContext ctx) throws Exception { // business logic Float erpAmount = ...get amount from erp-system...; Float processAmount = (Float) ctx.getContextInstance().getVariable("amount"); float result = erpAmount.floatValue() + processAmount.floatValue(); ...update erp-system with the result...; // graph execution propagation if (result > 5000) { ctx.leaveNode(ctx, "big amounts"); } else { ctx.leaveNode(ctx, "small amounts"); } } }
注記
6.10. グラフ実行
注記
wait state
のように挙動します。
wait state
に入るまで継続するようにしてみましょう。
wait state
中、 トークンをデータベースで永続化することができます。

図6.4 グラフ実行に関連するメソッド
leaving transition
を指定しなければなりません。 最初の遷移がデフォルトになります。 トークンへのシグナルで、 現ノードを取得し、Node.leave(ExecutionContext,Transition)
メソッドを呼びます (ExecutionContext
内のオブジェクトはトークンであるため、 ExecutionContext
はトークンであると考えるのがよいでしょう)。 メソッドは node-leave
イベントを発生させ、 Transition.take(ExecutionContext)
を呼び出します。 そのメソッドは遷移イベントを実行し、 遷移の 宛先ノードにある Node.enter(ExecutionContext)
を呼び出します。
execute
メソッドより実装されます。 各ノードは Node.leave(ExecutionContext,Transition)
を再び呼び出してグラフ実行を渡す役割を果たします。 要約は次の通りです。
Token.signal(Transition)
Node.leave(ExecutionContext,Transition)
Transition.take(ExecutionContext)
Node.execute(ExecutionContext)
Node.execute(ExecutionContext)
注記
6.11. トランザクション境界
token.signal()
や taskInstance.end()
は、 プロセスが新たに wait state
に入った時のみ返されます。
注記
async="true"
属性をすべてのノードでサポートします。非同期ノードはクライアントのスレッドで実行されません。代わりに、非同期メッセージングシステム上にメッセージが送信され、スレッドがクライアントに返されます (token.signal()
か taskInstance.end()
が返されます)。
org.jbpm.command.ExecuteNodeCommand
メッセージが、 非同期メッセージングシステムから jBPM Command Executor
へ送信されます。 これがキューからコマンドを読み取り、 コマンドを実行します。 org.jbpm.command.ExecuteNodeCommand
の場合、 ノードが実行されるとプロセスが継続されます。 各コマンドは個別のトランザクションで実行されます)。
重要
jBPM Command Executor
が実行しているようにしてください。 これには、 Web アプリケーションの CommandExecutionServlet
を設定します。
注記
wait state
になるまで全体の計算を行います (プロセスでトランザクションの境界を設定するには、 async="true"
を使用します)。
<start-state> <transition to="one" /> </start-state> <node async="true" name="one"> <action class="com...MyAutomaticAction" /> <transition to="two" /> </node> <node async="true" name="two"> <action class="com...MyAutomaticAction" /> <transition to="three" /> </node> <node async="true" name="three"> <action class="com...MyAutomaticAction" /> <transition to="end" /> </node> <end-state name="end" /> ...
//start a transaction JbpmContext jbpmContext = jbpmConfiguration.createContext(); try { ProcessInstance processInstance = jbpmContext.newProcessInstance("my async process"); processInstance.signal(); jbpmContext.save(processInstance); } finally { jbpmContext.close(); }
root token
は node one
を示し、 ExecuteNodeCommand
が、 コマンドエクセキュータへ送信されます。
node one
を実行します。 実行を渡すか、 それとも wait state
に入るのかをアクションが決定することができます。 アクションが実行を渡すよう決定した場合、 実行が node two
に入った時にトランザクションが終了します。
第7章 コンテキスト
注記
7.1. プロセス変数へのアクセス
org.jbpm.context.exe.ContextInstance
は、 プロセス変数の中心的なインターフェースとなります。 次のように ContextInstance
をプロセスインスタンスより取得します。
ProcessInstance processInstance = ...; ContextInstance contextInstance = (ContextInstance) processInstance.getInstance(ContextInstance.class);
void ContextInstance.setVariable(String variableName, Object value); void ContextInstance.setVariable( String variableName, Object value, Token token); Object ContextInstance.getVariable(String variableName); Object ContextInstance.getVariable(String variableName, Token token);
java.lang.String
です。 デフォルトでは、 ビジネスプロセスマネージャは次の値タイプをサポートします( Hibernate と永続する他のクラスもサポートします)。
java.lang.String | java.lang.Boolean |
java.lang.Character | java.lang.Float |
java.lang.Double | java.lang.Long |
java.lang.Byte | java.lang.Integer |
java.util.Date | byte[] |
java.io.Serializable |
注記
警告
7.2. 変数のライフ
java.util.Map
と同様に作成されます。 変数を削除することもできます。
ContextInstance.deleteVariable(String variableName); ContextInstance.deleteVariable(String variableName, Token token);
7.3. 変数の永続性
7.4. 変数スコープ
root token
トークンが使用されます。
root token
上に作成されます。 そのため、 デフォルトでは各変数はプロセススコープを持っています。 変数トークンを「ローカル」にするには、 次の例のように明示的に作成します。
ContextInstance.createVariable(String name, Object value, Token token);
7.4.1. 変数オーバーローディング
7.4.2. 変数オーバーライディング
contact
という変数を、shipping
および billing
のネストされた実行パスにある変数で上書きできます。
7.4.3. タスクインスタンス変数スコープ
7.5. 一時変数
注記
ProcessInstance
Java オブジェクトと同じです。
注記
processdefinition.xml
ファイルに宣言される必要はありません。
Object ContextInstance.getTransientVariable(String name); void ContextInstance.setTransientVariable(String name, Object value);
第8章 タスク管理
8.1. タスク
task-node
と process-definition
内で定義できます。 最も一般的な方法は、1つ以上のtask
をtask-node
で定義することです。その場合、task-node
は、 ユーザが行うタスクを表現し、プロセス実行は、アクターがタスクを終了するまで待機するはずです。 アクターがタスクを終了した時、プロセス実行は、継続します。 task-node
により多くのタスクが定義されたとき、 デフォルトの動作は、すべてのタスクが終了するまで待機します。
process-definition
上にも指定できます。 プロセス定義に指定されたタスクは、 名前でルックアップされ、task-node
の中から参照されるか、 またはアクションの中から利用することができます。 実は、すべての名前付きタスク(task-node
でも)は、process-definition
内で名前でルックアップできます。
priority
を設定できます。 このタスク向けに作成された各タスクインスタンスに対し、優先順位の初期値として利用されます (後ほど、この初期の優先順位を変更することも可能です)。
8.2. タスクインスタンス
actorId
(java.lang.String
) に割り当てることができます。 すべてのタスクインスタンスは、データベースの1つのテーブル (JBPM_TASKINSTANCE
) に 保存されます。 特定のactorId における全タスクインスタンスについて、このテーブルをクエリーすることで、その特定ユーザのタスクリストが取得できます。
8.2.1. タスクインスタンスのライフサイクル
注記
- タスクインスタンスは通常、プロセス実行で (
TaskMgmtInstance.createTaskInstance(...)
メソッドを使い)task-node
を入力すると作成されます - その後、ユーザーインターフェースのコンポーネントは、データベースをクエリし、タスクリストを入手します。
TaskMgmtSession.findTaskInstancesByActorId(...)
を使うことでクエリの実行ができます。 - 次に、ユーザーからの入力を集め、UIコンポーネントは
TaskInstance.assign(String)
、TaskInstance.start()
、あるいはTaskInstance.end(...)
を呼び出します。
create
start
end
TaskInstance
にある該当の"getter"でこれらのプロパティにアクセスします。
JBPM_TASKINSTANCE
テーブルには残っています。
8.2.2. タスクインスタンスとグラフ実行
task-node
を退場することはできません。デフォルトでは、タスクインスタンスはsignallingおよび non-blockingとなっています。
task-node
に関連付けられている場合、プロセス開発者は、タスクインスタンスが完了することでプロセスの継続にどのような影響与えるか指定することができます。task-node
のsignal-property
にこれらの値を渡します。
- last
- デフォルトです。最後のタスクインスタンスが終了しても実行を続けます。 このノードに入った際にタスクが作成されない場合、実行は継続されます。
- last-wait
- 最後のタスクインスタンスが終了しても実行を続けます。 このノードに入った際にタスクが作成されない場合、タスクノードにてタスクが作成されるまで実行を待機します。
- first
- 最初のタスクインスタンスが終了しても実行を続けます。 このノードに入った際にタスクが作成されない場合、実行は継続されます。
- first-wait
- 最初のタスクインスタンスが終了しても実行を続けます。 このノードに入った際にタスクが作成されない場合、タスクノードにてタスクが作成されるまで実行を待機します。
- unsynchronized
- この場合タスクの作成あるいは、未完了に拘らず常に実行は継続されます。
- never
- この場合、タスクの作成、あるいは未完了に拘らず、実行は継続されません。
task-node
の node-enter
イベント上の ActionHandler
へ追加し、create-tasks="false"
に設定します。 以下に例を示します。
public class CreateTasks implements ActionHandler { public void execute(ExecutionContext executionContext) throws Exception { Token token = executionContext.getToken(); TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance(); TaskNode taskNode = (TaskNode) executionContext.getNode(); Task changeNappy = taskNode.getTask("change nappy"); // now, 2 task instances are created for the same task. tmi.createTaskInstance(changeNappy, token); tmi.createTaskInstance(changeNappy, token); } }
task-node
に指定されます。 それらは、 process-definition
でも指定ができ TaskMgmtDefinition
からも取得できます (TaskMgmtDefinition
は、タスク管理情報を追加することで、プロセス定義をを継承します)。
TaskInstance.end()
を使い、タスクインスタンスの完了をマークします。任意で、endメソッドに遷移を指定できます。 タスクインスタンス完了が実行プロセスの継続を引き起こす場合、 指定された遷移を通るため、そのtask-node
から退場します。
8.3. 割り当て
task-node
には0個または1個以上のタスクが含まれます。タスクは、プロセス定義の一部であり静的な記述です。 実行時、タスクはタスクインスタンス作成の結果として発生します。 タスクインスタンスはユーザのタスクリストにおける1エントリに対応しています。
8.3.1. Assignment インターフェース
AssignmentHandler
インターフェース経由で行われます。
public interface AssignmentHandler extends Serializable { void assign( Assignable assignable, ExecutionContext executionContext ); }
AssignmentHandler
実装は、 タスクを割り当てるために 割り当て可能なメソッド ( setActorId
あるいはsetPooledActors
)を呼びだします。 割り当て可能なアイテムは、TaskInstance
あるいは SwimlaneInstance
(つまり、プロセスロール)です。
public interface Assignable { public void setActorId(String actorId); public void setPooledActors(String[] pooledActors); }
TaskInstance
とSwimlaneInstance
の両方を指定されたユーザか、アクターのプールに割り当てることができます。ユーザに TaskInstance
を割り当てるには、Assignable.setActorId(String actorId)
を呼び出します。 TaskInstance
をプールのアクター候補に割り当てるために、 Assignable.setPooledActors(String[] actorIds)
を呼び出します。
AssignmentHandler
を作成するには、processdefinition.xml
ファイルを使いそれぞれ設定します。割り当てハンドラへの設定を追加する方法については、 「委譲」 を参照してください。
8.3.2. 割り当てデータモデル
TaskInstance
は、actorId
と プールされたアクターのセットを保持しています

図8.1 割り当てモデルのクラス図
actorId
はタスクに対応するのに対し、プールされたアクターのセットはこれらの候補の集まりで、タスクを取得した場合その中の1つがそのタスクに対応することになります。actorId
および pooledActors
は任意で、組み合わせることも可能です。
8.3.3. パーソナルタスクリスト
TaskInstance
のactorId プロパティの存在で示します。以下の方法で、TaskInstance
を誰かのパーソナルタスクリストに置きます。
- task 要素の
actor-id
属性に表現を指定 - コードの任意の場所から
TaskInstance.setActorId(String)
メソッドを使用 AssignmentHandler
のassignable.setActorId(String)
を使用
TaskMgmtSession.findTaskInstances(String actorId)
を使用します。
8.3.4. グループタスクリスト
taskInstance
を置くには、ユーザーの actorId またはユーザーの groupIds
の1つを pooledActorIds
に追加する必要があります。以下のいずれかのメソッドを使い、プールされたアクターを指定します。
- このプロセスのtask要素の属性
pooled-actor-ids
に表現を指定 - コードの任意の場所から
TaskInstance.setPooledActorIds(String[])
を使用 - AssignmentHandlerの
assignable.setPooledActorIds(String[])
を使用
TaskMgmtSession.findPooledTaskInstances(String actorId)
またはTaskMgmtSession.findPooledTaskInstances(List actorIds)
を使用してすると、パーソナルタスクリストに存在せず(actorId==null
)、プールactorIdにマッチしないタスクインスタンスを検索できます。
注記
pooledActorId
のリストを持つ taskInstance はアクターのパーソナルタスクリストにのみ現れます。また、タスクインスタンスをグループに配置しなおすためにpooledActorId
を保持しますが、これはtaskInstance
の actorId プロパティを null
に設定するだけで行うことができます。
8.4. タスクインスタンス変数
8.5. タスクコントローラ
注記
- 中間のタスクインスタンス変数の更新によりプロセスが完了するまでにプロセス変数へ影響を与えないように、タスクインスタンス変数のコピーを作成します。この時、これらのコピーは再度プロセス変数にサブミットされます。
- タスクインスタンス変数は、プロセス変数に対して1対1の関係を持ちません。 例えば、プロセスに
sales in January
、sales in February
、sales in March
の変数があれば、タスクインスタンスのフォームは、この3カ月間の平均売上高を表示する必要があるかもしれません。

図8.2 タスクコントローラ
variable
要素のリストを取得します。
<task name="clean ceiling"> <controller> <variable name="a" access="read" mapped-name="x" /> <variable name="b" access="read,write,required" mapped-name="y" /> <variable name="c" access="read,write" /> </controller> </task>
read,write
です。
task-node
は多くのタスクを持つことができ、start-state
は 1 つのタスクを持つことができます。
TaskControllerHandler
実装を作成してください。以下がこのインターフェースです:
public interface TaskControllerHandler extends Serializable { void initializeTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token); void submitTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token); }
<task name="clean ceiling"> <controller class="com.yourcom.CleanCeilingTaskControllerHandler"> -- here goes your task controller handler configuration -- </controller> </task>
8.6. スイムレーン
assignment
が1つ存在します。詳細は 「割り当て」 を参照してください。
AssignmentHandler
が呼び出されます。 AssignmentHandler
に渡される Assignable
な項目 は、SwimlaneInstance
になります。特定のスイムレーン内のタスクインスタンスで実行される全assignment は伝播されます。特定のプロセスに関する知識を持つ人がタスクを取得するため、この動作はデフォルトとなっています。そのスイムレーンでそれ以降のタスクインスタンスはすべて、そのユーザーに自動的に割り当てられます。
8.7. 開始タスクのスイムレーン
Authentication.getAuthenticatedActorId()
メソッド経由でキャプチャーされ、 そのアクターは、開始タスクのスイムレーンに保存されます。
<process-definition> <swimlane name='initiator' /> <start-state> <task swimlane='initiator' /> <transition to='...' /> </start-state> ... </process-definition>
8.8. タスクイベント
task-create
、タスクインスタンス作成時にトリガーされます。task-assign
、タスクインスタンス割り当て時にトリガーされます。このイベント上で実行されるアクションでは、前回のアクターにexecutionContext.getTaskInstance().getPreviousActorId();
メソッドでアクセス可能である点に注意してください。task-start
、TaskInstance.start()
メソッドが呼び出されるとトリガーされます。このオプション機能を使い、ユーザーが実際にこのタスクインスタンスにて作業を開始していることを示します。task-end
、TaskInstance.end(...)
呼び出されるとトリガーされます。これはタスクの終了をマークします。 そのタスクが実行プロセスに関係している場合、この呼び出しは、実行プロセスの再開をトリガーするかもしれません。
注記
8.9. タスクタイマー
8.10. タスクインスタンスのカスタマイズ
TaskInstance
のサブクラスを作成します。org.jbpm.taskmgmt.TaskInstanceFactory
実装を作成します。jbpm.cfg.xml
ファイルの jbpm.task.instance.factory構成プロパティを完全修飾クラス名に設定することで、実装の設定を行います。TaskInstance
のサブクラスを利用している場合、 (extends="org.jbpm.taskmgmt.exe.TaskInstance"
を使い) そのサブクラスのHibernateマッピングファイルを作成してください。hibernate.cfg.xml
のリストにマッピングファイルを追加します。
8.11. アイデンティティコンポーネント
java.lang.String
として表現されます。そのため、組織モデルやデータ構造に関するいかなるナレッジも、JBPM コアエンジンの範囲外となります。
8.11.1. アイデンティティモデル

図8.3 アイデンティティモデルクラス図
User
は、ユーザかサービスを表します。Group
は、さまざまなユーザのグループです。 Group は、チーム、ビジネスユニット、及び会社全体の関係をモデルするようにネストすることが可能です。 Group は、 階層グループを区別するために、タイプを持っています (例:髪の色グループ)。 Membership
は、ユーザとグループ間で多対多関連を表しています。 メンバーシップは、会社でのポジションを表すのに利用できます。また、グループ内のユーザが行うロールを示すために、メンバーシップ名を使用することができます。
8.11.2. 割り当て式
<process-definition> <task-node name='a'> <task name='laundry'> <assignment expression='previous --> group(hierarchy) --> member(boss)' /> </task> <transition to='b' /> </task-node> <para>Syntax of the assignment expression is like this:</para> first-term --> next-term --> next-term --> ... --> next-term where first-term ::= previous | swimlane(swimlane-name) | variable(variable-name) | user(user-name) | group(group-name) and next-term ::= group(group-type) | member(role-name) </programlisting>
8.11.2.1. 最初の条件 (First term)
User
か Group
を指定します。 その後の条件は中間ユーザかグループから次の条件を算出します。
previous
は、タスクが、現在の承認済みアクターに割り当てられていることを意味します。 これは、プロセス中で前回のステップで動作したアクターということになります。
swimlane(swimlane-name)
は、 ユーザやグループが、指定されたスイムレーンインスタンスから取得されるということです。
variable(variable-name)
は、ユーザやグループが指定された変数インスタンスから取得されるということです。 変数インスタンスには、java.lang.String
を含めることができます。 その場合、そのユーザやグループがアイデンティティコンポーネントから取得されます。もしくは、変数インスタンスは、 User
やGroup
のオブジェクトを含みます。
user(user-name)
は、特定のユーザがアイデンティティコンポーネントから取得されるということです。
group(group-name)
は特定のグループが、アイデンティティコンポーネントから取得されるということです。
8.11.2.2. 次の条件(Next term)
group(group-type)
は、ユーザーのグループを取得します。 前回の条件は、User
でなければなりません。そのユーザーの全メンバーシップの中で指定のgroup-type を用いてグループの検索を行います。
member(role-name)
はグループ内で指定のロールを実行するユーザーを取得します。 前回の条件は Group
でなければなりません。この条件では、当グループへのメンバーシップを持つユーザーのうち、メンバーシップ名が指定の role-nameに一致するものを検索します。
8.11.3. アイデンティティコンポーネントの削除
hibernate.cfg.xml
より次の行を削除するだけで JBPM アイデンティティーコンポーネントを削除することができます。
<mapping resource="org/jbpm/identity/User.hbm.xml"/> <mapping resource="org/jbpm/identity/Group.hbm.xml"/> <mapping resource="org/jbpm/identity/Membership.hbm.xml"/>
ExpressionAssignmentHandler
が、アイデンティティコンポーネントに依存しているためそのままで利用することはできません。 ExpressionAssignmentHandler
を再利用して、利用中のユーザデータストアにバインドしたい場合、 ExpressionAssignmentHandler
を拡張して、getExpressionSession
メソッドをオーバーライドできます。
protected ExpressionSession getExpressionSession(AssignmentContext assignmentContext);
第9章 スケジューラー
9.1. タイマー
<state name='catch crooks'> <timer name='reminder' duedate='3 business hours' repeat='10 business minutes' transition='time-out-transition' > <action class='the-remainder-action-class-name' /> </timer> <transition name='time-out-transition' to='...' /> </state>
timer
タイプのイベントが発生します。- アクションの指定がある場合、 アクションが実行されます。
- 指定された遷移でシグナルが実行を再開します。
timer
要素に名前が指定されていない場合、 デフォルトでノード名がタイマー名になります。
action
や script
など)。
action-elements
はcreate-timer
と cancel-timer
です。 前述のタイマー要素は、 node-enter
上の create-timer
アクションと node-leave
上のcancel-timer
アクションを略したものになります。
9.2. スケジューラーデプロイメント
timer runner
がこのストアをチェックし、 各タイマーを実行します。

図9.1 スケジューラーコンポーネントの概要
第10章 非同期の続行
10.1. コンセプト
async="true"
で非同期に続行するよう指定できます。 async="true"
は、 イベントでトリガーされ、 すべてのノードタイプとすべてのアクションタイプで指定できる場合のみサポートされます。
10.2. 例

図10.1 サンプル 1: 非同期の続行がないプロセス
GraphSession.saveProcessInstance
の呼び出しにより、Hibernate によって生成されます。2番目に自動化アクションがトランザクションリソースにアクセスし更新する場合、このような更新は同じトランザクションと組み合わされるか同じトランザクションの一部となるはずです
async="true"
属性を設定するとノードが非同期としてマークされます。
async="true"
を'b'ノードに追加した結果、プロセス実行は、2つに分かれます。 最初の部分は、'b'ノードが実行されるところまで、実行していきます。 2つ目の部分は、'b'ノードを実行し、'c'ノードの待機状態で止まります。
Token.signal
メソッドの呼び出し) を求めますが、2つ目のトランザクションは、自動的に呼び出されて実行されます。

図10.2 非同期続行のプロセス
async="true"
でマークされたアクションは、プロセス実行のスレッド外で実行されます。 永続化の設定がされている場合(デフォルトです)、アクションは別々のトランザクションで実行されます。
10.3. ジョブエグゼキューター
ExecuteNodeJob
と ExecuteActionJob
です。
Job
(POJO) が MessageService
へ送信されます。 メッセージサービスは JbpmContext
と関連付けられ、 送信する必要があるすべてのメッセージを収集します。
JbpmContext.close()
の一部として送信されます。 このメソッドは関連付けられたすべてのサービスに対して close()
呼び出しをカスケード処理します。 実際のサービスは jbpm.cfg.xml
で設定できます。 サービスの 1 つ DbMessageService
はデフォルトで設定され、 新しいジョブメッセージが利用可能であることをジョブエクゼキュータに通知します。
MessageServiceFactory
インターフェースと MessageService
インターフェースを使用してメッセージを送信します。 これにより非同期メッセージサービスが設定可能になります (jbpm.cfg.xml
)。 Java EE 環境では、 DbMessageService
を JmsMessageService
に置き換えて、 アプリケーションサーバーの機能を活用できます。
- ジョブエグゼキュータースレッドはジョブを取得する必要がある
- ジョブエグゼキュータースレッドはジョブを取得する必要がある
REPEATABLE_READ
にセットする必要があります。 REPEATABLE_READ
により、 このクエリが 1 つの競合トランザクションで 1 つの行のみを更新することが保証されます。
update JBPM_JOB job set job.version = 2 job.lockOwner = '192.168.1.3:2' where job.version = 1
READ_COMMITTED
は Non-Repeatable Reads の発生を許すため、十分ではありません。したがって、複数のジョブエグゼキュータースレッドを設定する場合はREPEATABLE_READ
が必要です。
- jbpmConfiguration
- 設定をリトリーブする bean
- name
- ジョブエグゼキューター名
重要
1 台のマシンに JBPM インスタンスが 1 つ以上、開始されている場合、この名前は各ノードに一意でなければなりません。 - nbrOfThreads
- 開始されたエグゼキュータースレッドの数
- idleInterval
- 保留されているジョブがない場合、ディスパッチャースレッドがジョブのキューを確認するまでに待機する時間
注記
キューにジョブが追加されると、ディスパッチャースレッドに自動通知されます。 - retryInterval
- 実行時に問題があった場合のジョブ再試行の間隔。デフォルト値は 3 回です。
注記
再試行の最大回数は jbpm.job.retries で設定されています。 - maxIdleInterval
- idleInterval の最大期間
- historyMaxSize
- このプロパティは廃止されるため、特に影響はありません。
- maxLockTime
- lock-monitor スレッドがアンロックするまでジョブをロックできる最大時間
- lockMonitorInterval
- lock-monitor スレッドがロックされているジョブの確認をする際の休止間隔
- lockBufferTime
- このプロパティは廃止されるため、特に影響はありません。
10.4. JBPM 組み込み非同期メッセージング
JBPM_JOB
テーブルに保存されます。
org.jbpm.msg.command.CommandExecutor
) は、データベースのテーブルからメッセージを読み取り、実行します。 つまり、典型的な POJO コマンドエグゼキューターのトランザクションは以下のようになります。
- 次のコマンドメッセージの読み込み
- コマンドメッセージの実行
- コマンドメッセージの削除

図10.3 POJO コマンドエグゼキュータートランザクション
重要
第11章 ビジネスカレンダー
11.1. Due Date (期限)
duedate ::= [<basedate> +/-] <duration>
になります。
11.1.1. Duration (期間)
duration ::= <quantity> [business] <unit>
を公式として使用し、 絶対時間または営業時間のいずれかで指定されます。
<quantity>
は Double.parseDouble(quantity)
で解析可能なテキストでなければなりません。 <unit>
は、 second、 seconds、 minute、 minutes、 hour、 hours、 day、 days、 week、 weeks、 month、 months、 year、 years のいずれかになります。 任意の business
フラグを追加すると、 営業時間のみが期間で考慮されます。 business
を指定しないと、 期間は絶対期間として解釈されます。
11.1.2. 基準日
basedate ::= <EL>
のように計算されます。
<EL>
は Java Date
または Calendar
オブジェクトへ解決する Java 表現言語になります。
警告
JbpmException
エラーが発生するため、 他のオブジェクトタイプの変数を参照しないようにしてください。
11.1.3. 期限の例
<timer name="daysBeforeHoliday" duedate="5 business days">...</timer> <timer name="pensionDate" duedate="#{dateOfBirth} + 65 years" >...</timer> <timer name="pensionReminder" duedate="#{dateOfPension} - 1 year" >...</timer> <timer name="fireWorks" duedate="#{chineseNewYear} repeat="1 year" >...</timer> <reminder name="hitBoss" duedate="#{payRaiseDay} + 3 days" repeat="1 week" />
11.2. カレンダー設定
org/jbpm/calendar/jbpm.business.calendar.properties
ファイルに営業時間を指定します (この設定ファイルをカスタマイズするには、変更したコピーをクラスパスのルートに置きます)。
jbpm.business.calendar.properties
にあるデフォルトの営業時間の仕様になります。
hour.format=HH:mm #weekday ::= [<daypart> [& <daypart>]*] #daypart ::= <start-hour>-<to-hour> #start-hour and to-hour must be in the hour.format #dayparts have to be ordered weekday.monday= 9:00-12:00 & 12:30-17:00 weekday.tuesday= 9:00-12:00 & 12:30-17:00 weekday.wednesday= 9:00-12:00 & 12:30-17:00 weekday.thursday= 9:00-12:00 & 12:30-17:00 weekday.friday= 9:00-12:00 & 12:30-17:00 weekday.saturday= weekday.sunday= day.format=dd/MM/yyyy # holiday syntax: <holiday> # holiday period syntax: <start-day>-<end-day> # below are the belgian official holidays holiday.1= 01/01/2005 # nieuwjaar holiday.2= 27/3/2005 # pasen holiday.3= 28/3/2005 # paasmaandag holiday.4= 1/5/2005 # feest van de arbeid holiday.5= 5/5/2005 # hemelvaart holiday.6= 15/5/2005 # pinksteren holiday.7= 16/5/2005 # pinkstermaandag holiday.8= 21/7/2005 # my birthday holiday.9= 15/8/2005 # moederkesdag holiday.10= 1/11/2005 # allerheiligen holiday.11= 11/11/2005 # wapenstilstand holiday.12= 25/12/2005 # kerstmis business.day.expressed.in.hours= 8 business.week.expressed.in.hours= 40 business.month.expressed.in.business.days= 21 business.year.expressed.in.business.days= 220
11.3. 使用例
<timer name="daysBeforeHoliday" duedate="5 business days">...</timer> <timer name="pensionDate" duedate="#{dateOfBirth} + 65 years" >...</timer> <timer name="pensionReminder" duedate="#{dateOfPension} - 1 year" >...</timer> <timer name="fireWorks" duedate="#{chineseNewYear} repeat="1 year" >...</timer> <reminder name="hitBoss" duedate="#{payRaiseDay} + 3 days" repeat="1 week" />
hour.format=HH:mm #weekday ::= [<daypart> [& <daypart>]*] #daypart ::= <start-hour>-<to-hour> #start-hour and to-hour must be in the hour.format #dayparts have to be ordered weekday.monday= 9:00-12:00 & 12:30-17:00 weekday.tuesday= 9:00-12:00 & 12:30-17:00 weekday.wednesday= 9:00-12:00 & 12:30-17:00 weekday.thursday= 9:00-12:00 & 12:30-17:00 weekday.friday= 9:00-12:00 & 12:30-17:00 weekday.saturday= weekday.sunday= day.format=dd/MM/yyyy # holiday syntax: <holiday> # holiday period syntax: <start-day>-<end-day> # below are the belgian official holidays holiday.1= 01/01/2005 # nieuwjaar holiday.2= 27/3/2005 # pasen holiday.3= 28/3/2005 # paasmaandag holiday.4= 1/5/2005 # feest van de arbeid holiday.5= 5/5/2005 # hemelvaart holiday.6= 15/5/2005 # pinksteren holiday.7= 16/5/2005 # pinkstermaandag holiday.8= 21/7/2005 # my birthday holiday.9= 15/8/2005 # moederkesdag holiday.10= 1/11/2005 # allerheiligen holiday.11= 11/11/2005 # wapenstilstand holiday.12= 25/12/2005 # kerstmis business.day.expressed.in.hours= 8 business.week.expressed.in.hours= 40 business.month.expressed.in.business.days= 21 business.year.expressed.in.business.days= 220
第12章 電子メールサポート
12.1. JPDL でのメール
12.1.1. メールアクション
注記
<mail actors="#{president}" subject="readmylips" text="nomoretaxes" />
<mail actors="#{president}" > <subject>readmylips</subject> <text>nomoretaxes</text> </mail>
<mail to='#{initiator}' subject='websale' text='your websale of #{quantity} #{item} was approved' />
注記
<mail to='admin@mycompany.com' subject='urgent' text='the mailserver is down :-)' />
注記
<mail template='sillystatement' actors="#{president}" />
注記
12.1.2. メールノード
mail action
と全く同じ属性と要素をエレメントをサポートします (詳細は 「メールアクション」 を参照してください)。
<mail-node name="send email" to="#{president}" subject="readmylips" text="nomoretaxes"> <transition to="the next node" /> </mail-node>
重要
12.1.3. タスクが割り当てられた電子メール
notify="yes"
属性を使用してください。
<task-node name='a'> <task name='laundry' swimlane="grandma" notify='yes' /> <transition to='b' /> </task-node>
yes
、 true
、 on
のいずれかに設定して、 タスクに割り当てられたアクターへビジネスプロセスマネージャーが電子メールを送信するようにします (電子メールはテンプレートを基とし、 Web アプリケーションのタスクページへのリンクが含まれています)。
12.1.4. タスクリマインダ電子メール
<task-node name='a'> <task name='laundry' swimlane="grandma" notify='yes'> <reminder duedate="2 business days" repeat="2 business hours"/> </task> <transition to='b' /> </task-node>
12.2. メールにおける表現
jbpm.cfg.xml
ファイルより設定します。
president
と呼ばれる swimlane が存在することを仮定しています。
<mail actors="#{president}" subject="readmylips" text="nomoretaxes" />
president
となる人へ電子メールを送信します。
12.3. メール受信者の指定
12.3.1. 複数の受信者
12.3.2. BCC アドレスへ電子メールを送信
<mail to='#{initiator}' bcc='bcc@mycompany.com' subject='websale' text='your websale of #{quantity} #{item} was approved' />
jbpm.cfg.xml
で集中的に設定された場所へ送信する方法もあります 。次の例を参考にしてみてください。
<jbpm-configuration> ... <string name="jbpm.mail.bcc.address" value="bcc@mycompany.com" /> </jbpm-configuration>
12.3.3. アドレス解決
actorIds
によって参照されます。 これはプロセス参加者を識別する文字列です。 アドレスリゾルバー は actorIds
を電子メールアドレスに変換します。
public interface AddressResolver extends Serializable { Object resolveAddress(String actorId); }
actorId
の電子メールアドレスを表します)。
jbpm.mail.address.resolver
という名前で jbpm.cfg.xml
ファイルに設定されなければなりません。
<jbpm-configuration> <bean name='jbpm.mail.address.resolver' class='org.jbpm.identity.mail.IdentityAddressResolver' singleton='true' /> </jbpm-configuration>
identity
コンポーネントにはアドレスリゾルバーが含まれています。このアドレスリゾルバーは指定 actorId
のユーザーを検索します。ユーザーが存在する場合、 ユーザーの電子メールアドレスが返されます。存在しない場合は null が返されます。
注記
12.4. 電子メールテンプレート
processdefinition.xml
ファイルを使用して電子メールを指定する代わりにテンプレートを使用することもできます。 この場合でも、 各フィールドは processdefinition.xml
によって上書きされます。 次のようにテンプレートを指定します。
<mail-templates> <variable name="BaseTaskListURL" value="http://localhost:8080/jbpm/task?id=" /> <mail-template name='task-assign'> <actors>#{taskInstance.actorId}</actors> <subject>Task '#{taskInstance.name}'</subject> <text><![CDATA[Hi, Task '#{taskInstance.name}' has been assigned to you. Go for it: #{BaseTaskListURL}#{taskInstance.id} Thanks. ---powered by JBoss jBPM---]]></text> </mail-template> <mail-template name='task-reminder'> <actors>#{taskInstance.actorId}</actors> <subject>Task '#{taskInstance.name}' !</subject> <text><![CDATA[Hey, Don't forget about #{BaseTaskListURL}#{taskInstance.id} Get going ! ---powered by JBoss jBPM---]]></text> </mail-template> </mail-templates>
jbpm.cfg.xml
ファイルよりテンプレートを含むリソースを設定します。
<jbpm-configuration> <string name="resource.mail.templates" value="jbpm.mail.templates.xml" /> </jbpm-configuration>
12.5. メールサーバーの設定
jbpm.cfg.xml
ファイルの jbpm.mail.smtp.host プロパティを設定してメールサーバーを設定します。
<jbpm-configuration> <string name="jbpm.mail.smtp.host" value="localhost" /> </jbpm-configuration>
<jbpm-configuration> <string name='resource.mail.properties' value='jbpm.mail.properties' /> </jbpm-configuration>
12.6. 送信者アドレスの設定
From
アドレスフィールドのデフォルト値は jbpm@noreply
です。 次のように、 キー jbpm.mail.from.address
を使って jbpm.xfg.xml
ファイルで設定します。
<jbpm-configuration> <string name='jbpm.mail.from.address' value='jbpm@yourcompany.com' /> </jbpm-configuration>
12.7. 電子メールサポートのカスタマイズ
org.jbpm.mail.Mail
に中央化されています。このクラスは ActionHandler
実装です。電子メールが process
XML に指定されると、mail
クラスに委譲されます。 mail
クラスから継承し、必要に応じて動作をカスタマイズすることができます。メール委譲に使用するクラスを設定するには、以下のように jbpm.cfg.xml
で jbpm.mail.class.name
設定文字列を指定します。
<jbpm-configuration> <string name='jbpm.mail.class.name' value='com.your.specific.CustomMail' /> </jbpm-configuration>
第13章 ロギング
注記
13.1. ログの作成
org.jbpm.logging.log.ProcessLog
を継承する Java オブジェクトです)。 プロセスログエントリは、 ProcessInstance
の任意拡張である LoggingInstance
に追加されます。
inheritance tree
をナビゲートできるため、 org.jbpm.logging.log.ProcessLog
から開始するとよいでしょう。
LoggingInstance
はすべてのログエントリを収集します。 ProcessInstance
が保存されると、 データベースへフラッシュされます (ProcessInstance
の logs フィールドは Hibernate へマップされていません。 これは、 各トランザクションでデータベースより読み取られるログを回避するためです)。
ProcessInstance
は実行パスのコンテキストで作成されます。 そのため、 ProcessLog
は インデックスシーケンスジェネレータ ともなるそのトークンを参照します (後続のトランザクションによって作成されたログは順次的なシーケンス番号が付けられるため、 ログの読み出しに重要となります)。
public class LoggingInstance extends ModuleInstance { ... public void addLog(ProcessLog processLog) {...} ... }

図13.1 JBPM ロギング情報クラス図
public class LoggingInstance extends ModuleInstance { ... public void startCompositeLog(CompositeLog compositeLog) {...} public void endCompositeLog() {...} ... }
CompositeLog
は常に try-finally-block
で呼び出されなければなりません。 例は次の通りです。
startCompositeLog(new MyCompositeLog()); try { ... } finally { endCompositeLog(); }
13.2. ログの設定
jbpm.cfg.xml
設定ファイルの jbpm-context セクションのロギング行を削除してください。
<service name='logging' factory='org.jbpm.logging.db.DbLoggingServiceFactory' />
LoggingService
(DbLoggingService
のサブクラス) のカスタム実装を記述します。 その後、 ロギングのカスタム ServiceFactory
を作成し、 factory
属性に指定します。
13.3. ログの読み出し
LoggingSession
による 2 つのメソッドがあります。
ProcessLogs
のリストをプロセスインスタンスの全トークンに関連付けます。 リストには ProcessLogs
が作成順に記載されます。
public class LoggingSession { ... public Map findLogsByProcessInstance(long processInstanceId) {...} ... }
ProcessLogs
が作成順に記載されます。
public class LoggingSession { public List findLogsByToken(long tokenId) {...} ... }
第14章 JBPM プロセス定義言語
14.1. プロセスアーカイブ
processdefinition.xml
となっています。 このファイルに含まれる主な情報は、プロセスグラフです (アクションやタスクの情報も含まれています)。 processdefinition.xml
には、 アクションとタスクについての情報も含まれています。また、プロセスアーカイブにはタスクが必要とするクラスやユーザーインターフェース (UI) フォームなど、他のプロセス関連ファイルを格納することもできます。
14.1.1. プロセスアーカイブのデプロイ
process archive
は、以下の3つの方法でデプロイ可能です。
- Process Designer Tool
ant
タスク- プログラム
starter's kit
で対応しています)。
- プロセスアーカイブフォルダーを右クリックし、オプションを選択します。
starter's kit
サーバーには JBPM アプリケーションが含まれており、このアプリケーションにはProcessUploadServlet
と呼ばれるプロセスアーカイブをアップロードするサーブレットが存在します。このサーブレットはプロセスアーカイブをアップロードし、それをデフォルトの JBPM インスタンスにデプロイできます。
ant
タスクでプロセスをデプロイを行うには、以下のコードを使います。
<target name="deploy-process"> <taskdef name="deployproc" classname="org.jbpm.ant.DeployProcessTask"> <classpath location="jbpm-jpdl.jar" /> </taskdef> <deployproc process="build/myprocess.par" /> </target>
ant
タスクの他の属性は以下の通りです。
表14.1 Ant 属性
属性 | 説明 | 必要性 |
---|---|---|
process |
プロセスアーカイブへのパス
|
ネスト化されたリソースコレクション要素を利用していなければ YES
|
jbpmcfg |
デフォルト値は、
jbpm.cfg.xml です。 JBPM 設定ファイルは、 データベースおよびマッピングファイルの JDBC 接続プロパティを含む Hibernate 設定ファイルの場所を指定できます (デフォルト値は hibernate.cfg.xml )。
|
No、
jbpm.cfg.xml がデフォルト
|
failonerror |
false の場合、警告メッセージをログに残しますが、プロセス定義がデプロイに失敗してもビルドは停止されません。True に設定されている場合、プロセス定義の1つのデプロイメントに失敗するとデプロイメントタスクが即座にエラーで失敗します。
| No。True がデフォルト |
org.jbpm.jpdl.par.ProcessArchiveDeployer
クラスの parseXXX
の1つを使って、プログラムでデプロイできます。
14.1.2. プロセスバージョニング
- これらのクラスが JBPM クラスローダーで参照可能にすること参照できるようにするには、プロセス定義のすべてがクラスファイルを参照するように
jbpm-[version].jar
の隣にある.JAR
ファイルに委譲クラスを置きます。また、 Java クラスはプロセスアーカイブにも含めることができます。プロセスアーカイブに委譲クラスを含めると (jbpm クラスローダーからは可視できません)、JBPM はプロセス定義内でこれらのクラスをバージョン管理します。注記
プロセスのクラスローディングに関する詳細は、「委譲」を参照してください。
-1
です)。
14.1.3. デプロイ済プロセス定義の変更
警告
org.jbpm.db.GraphSession
のloadProcessDefinition
メソッド、findProcessDefinition
メソッドでロードされるか、関係付けによりロードされるプロセス定義を更新する際の制限はありません。にもかかわらず、setStartState(null)
などの呼び出しでプロセスが非常に簡単に混乱してしまいます。- プロセス定義を変更すべきではないため、同梱の Hibernate 設定が定義クラスやコレクションの
nonstrict-read-write
キャッシュ戦略を指定します。この定義は、コミットされていない更新に関しても他のトランザクションで見えるようにできます。
14.1.4. プロセスインスタンスの移行
注記
ChangeProcessInstanceVersionCommand
を実行してください。
new ChangeProcessInstanceVersionCommand() .processName("commute") .nodeNameMappingAdd("drive to destination", "ride bike to destination") .execute(jbpmContext);
14.2. 委譲
14.2.1. JBPMクラスローダー
jbpm-3.x.jar
の横に置きます。Web アプリケーションの場合には jbpm-jpdl.jar
とともに WEB-INF/lib
ディレクトリにカスタムの JAR ファイルを置きます。
14.2.2. プロセスクラスローダ
/classes
ディレクトリ内に置くことでクラスをプロセス定義に追加できます。 これはプロセス定義に追加したいクラスにバージョニングしたいときにだけ役に立つことに注意してください。 バージョニングが必要ない場合には、代わりに JBPM クラスローダーでクラスを利用可能にします。
/classes
ディレクトリからもロードされます。このディレクトリの外部にあるリソースをロードする場合は、スラッシュを 2つ (//
) 先頭に指定します (たとえば、プロセスアーカイブファイルのルートにある data.xml
をロードするには、class.getResource("//data.xml")
を呼び出します。
14.2.3. 委譲設定
ActionHandler
インターフェースの実装は、プロセスのイベントに対して呼びだされます。委譲は、processdefinition.xml
ファイルで指定されます。委譲を指定するときには、3 つのデータを提供します。
- クラス名(必須) : 委譲クラスの完全修飾名
- 設定タイプ (任意): 委譲オブジェクトのインスタンス化と設定方法を指定します。 デフォルトでは、デフォルトコンストラクターが利用され、設定情報は無視されます。
- 設定 (任意): 設定タイプに応じたフォーマットで記述された委譲オブジェクトの設定
14.2.3.1. config-type フィールド
- 文字列は省略されますが変換されません。
- int, long, float, double, ...などのプリミティブ型
- プリミティブ型の基礎ラッパークラス
- list と, set と collection。 その場合、xml コンテンツの各要素は collection の 要素として扱われ、再帰的に変換しながら パースされます。要素の型が
java.lang.String
と異なる場合、 完全修飾型名で type 属性を指定することによって示すことができます。 例えば、以下のコードは numbersフィールドに 文字列 のArrayList
をインジェクトします:<numbers> <element>one</element> <element>two</element> <element>three</element> </numbers>
要素内のテキストはStringコンストラクターをもつ、いかなるオブジェクトにでも変換できます。 他のString型でない他のものを利用する場合、このフィールドにてelement-typeで指定します。 (この場合はnumbers)これがMapの別例です。<numbers> <entry><key>one</key><value>1</value></entry> <entry><key>two</key><value>2</value></entry> <entry><key>three</key><value>3</value></entry> </numbers>
- この場合、fieldの各要素には、子要素 key1つとvalue のサブ要素1つが必要です。これらは、変換ルールを利用して再帰的にパースされます。 ちょうど collections と同じように、type 属性が指定されていなければ
java.lang.String
への変換が想定されます。 org.dom4j.Element
- その他のタイプのために、String コンストラクタが利用されます
public class MyAction implements ActionHandler { // access specifiers can be private, default, protected or public private String city; Integer rounds; ... }
... <action class="org.test.MyAction"> <city>Atlanta</city> <rounds>5</rounds> </action> ...
14.2.3.2. config-type Bean
14.2.3.3. config-type コンストラクター
14.2.3.4. config-type configuration-property
void configure(String);
メソッドに渡します。
14.3. 式
expression="#{myVar.handler[assignments].assign}"
のように記述することができます。
注記
#{...}
を利用し、メソッドバインディングのサポートを含みます。
- taskInstance (
org.jbpm.taskmgmt.exe.TaskInstance
) - processInstance (
org.jbpm.graph.exe.ProcessInstance
) - processDefinition (
org.jbpm.graph.def.ProcessDefinition
) - token (
org.jbpm.graph.exe.Token
) - taskMgmtInstance (
org.jbpm.taskmgmt.exe.TaskMgmtInstance
) - contextInstance (
org.jbpm.context.exe.ContextInstance
)
14.4. JPDL XML スキーマ
processdefinition.xml
ファイル で利用されるスキーマです。
14.4.1. バリデーション
- スキーマは XML ドキュメントで参照されます。
<process-definition xmlns="urn:jbpm.org:jpdl-3.2"> ... </process-definition>
- Xerces パーサーがクラスパス上にあります。
注記
${jbpm.home}/src/java.jbpm/org/jbpm/jpdl/xml/jpdl-3.2.xsd
か、http://jbpm.org/jpdl-3.2.xsdにあります。
14.4.2. プロセス定義
表14.2 プロセス定義スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | プロセス名 |
swimlane | 要素 | [0..*] | プロセスで利用されるスイムレーン。スイムレーンはプロセス役割を表してタスク割り当てで利用されます。 |
start-state | 要素 | [0..1] | プロセスの開始状態。 開始状態のないプロセスは有効ですが、実行することができないことに注意してください。 |
{end-state|state|node|task-node|process-state|super-state|fork|join|decision} | 要素 | [0..*] | プロセス定義のノード。ノードのないプロセスは有効ですが、実行することができないことに注意してください。 |
event | 要素 | [0..*] | アクションのコンテナとしてサービス提供 |
{action|script|create-timer|cancel-timer} | 要素 | [0..*] | グローバルに定義されたアクションでイベントと遷移から参照可能。これらのアクションは名前を指定することで参照する必要があることに注意してください。 |
task | 要素 | [0..*] | アクションなどで使用できるグローバルに定義されたタスク |
exception-handler | 要素 | [0..*] | このプロセス定義で委譲クラスによってスローされたすべてのエラーに適用される例外ハンドラのリスト |
14.4.3. node
表14.3 Node スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
{action|script|create-timer|cancel-timer} | 要素 | 1 | このノードの動作を表すカスタムアクション |
一般的なノード要素 | 「一般的なノード要素」 |
14.4.4. 一般的なノード要素
表14.4 共通ノードスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 必須 | ノードの名前 |
async | 属性 | { true | false }, falseがデフォルト値 | true に設定されている場合、 このノードは非同期で実行されます。 10章非同期の続行 も参照してください。 |
transition | 要素 | [0..*] | 退場遷移。ノ ードを退場する遷移は一意の名前を持たなければいけません。 名前がなくても許可される退場遷移は最大 1 つです。 最初に指定されている遷移はデフォルト遷移と呼ばれます。 デフォルト遷移は、遷移名を指定せずにノードが退場する時に使用されます。 |
event | 要素 | [0..*] | サポートされているイベントタイプ: {node-enter|node-leave} |
exception-handler | 要素 | [0..*] | プロセスノードから委譲クラスによってスローされたすべての例外に適用される例外ハンドラのリスト |
timer | 要素 | [0..*] | このノードで実行の時間を監視するタイマーを指定します。 |
14.4.5. start-state
表14.5 開始状態スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | ノードの名前 |
task | 要素 | [0..1] | このプロセスに対して新しいインスタンスを起動するするタスクまたはプロセスイニシエータをキャプチャーするタスク。 「開始タスクのスイムレーン」 を参照 |
event | 要素 | [0..*] | サポートされているイベントタイプ: {node-leave} |
transition | 要素 | [0..*] | 退場遷移。ノードを退場する各遷移は一意の名前を持つ必要があります。 |
exception-handler | 要素 | [0..*] | プロセスノードから委譲クラスによってスローされたすべての例外に適用される例外ハンドラのリスト |
14.4.6. end-state
表14.6 終了状態スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 必須 | 終了状態の名前 |
end-complete-process | 属性 | 任意 | デフォルトでは、end-complete-process は false であるため、 この end-state を終了するトークンのみが終了されます。 このトークンが最後に終了する子トークンである場合、親トークンも再帰的に終了されます。 このプロパティを true に設定すると、 全体のプロセスインスタンスが終了されます。 |
event | 要素 | [0..*] | サポートされているイベントタイプ: {node-enter} |
exception-handler | 要素 | [0..*] | プロセスノードから委譲クラスによってスローされたすべての例外に適用される例外ハンドラのリスト |
14.4.7. state
表14.7 状態スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.8. task-node
表14.8 タスクノードスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
signal | 属性 | 任意 | {unsynchronized|never|first|first-wait|last|last-wait} 、デフォルト値はlast です。プロセス実行継続のタスク完了にどのように影響を与えるか指定します。 |
create-tasks | 属性 | 任意 | {yes|no|true|false} 、デフォルト値はtrue です。ランタイム時に作成する必要があるタスクを決定しなければならない場合は、false に設定できます。この場合は、アクションを node-enterに追加し、アクションにタスクを作成して、create-tasksをfalse に設定します。 |
end-tasks | 属性 | 任意 | {yes|no|true|false} 、デフォルト値はfalse です。remove-tasks がnode-leaveでtrue に設定されている場合、開いているタスクはすべて終了されます。 |
task | 要素 | [0..*] | このタスクノードに到着したときに、作られるタスク |
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.9. process-state
表14.9 プロセス状態スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
sub-process | 要素 | 1 | バージョンと binding="late" が与えられると、JBPM はバージョン属性を無視し最新のバージョンを使います。 |
variable | 要素 | [0..*] | データを起動時にスーパープロセスからサブプロセスにどのようにコピーするかとデータをサブプロセスの完了時にサブプロセスからスーパープロセスにどのようにコピーするかを指定します。 |
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.10. super-state
表14.10 親状態 (superstate) スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
{end-state|state|node|task-node|process-state|super-state|fork|join|decision} | 要素 | [0..*] | super-state のノード。super-state はネスト化できます。 |
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.11. fork
表14.11 Fork スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.12. join
表14.12 Join スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.13. decision
表14.13 Decision スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
handler | 要素 | 遷移上の 'handler' のエレメント、又は条件を指定する必要があります。 | org.jbpm.jpdl.Def.DecisionHandler 実装の名前 |
遷移の条件 | 決定を退場する遷移の属性または要素テキスト | 遷移にはすべてガード条件が存在します。決定ノードは、条件付きの退出遷移を検証し、条件が true の最初の遷移を選択します。条件を満たすものがない場合、デフォルト の遷移が選択されます。デフォルトの遷移は、無条件の遷移がある場合は最初のものを、そうでない場合は最初の条件付き遷移となっています。遷移は文書順に考慮されます。 | |
一般的なノード要素 | 「一般的なノード要素」 を参照 |
14.4.14. event
表14.14 イベントスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
type | 属性 | 必須 | これはイベントタイプで、イベントが置かれた要素に対して相対的に表されます。 |
{action|script|create-timer|cancel-timer} | 要素 | [0..*] | このイベントで実行すべきアクションのリスト |
14.4.15. transition
表14.15 遷移スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | 遷移の名前。ノードを退場する各遷移は一意の名前を持つ必要があることに注意してください。 |
to | 属性 | 必須 | 宛先ノードの階層名。 階層名の詳細については、「階層名」を参照してください。 |
condition | 属性または要素テキスト | 任意 | ガード条件表現。これらの条件属性 (または子要素) を決定ノードで使用、あるいは ランタイム時にトークンで利用可能な遷移を計算するために使用できます。決定ノードを退出する遷移でのみ条件設定が可能です。 |
{action|script|create-timer|cancel-timer} | 要素 | [0..*] | この遷移の発生時に実行するアクション。遷移のアクションをイベントに配置する必要がないことに注意してください(遷移は1つしかないためです)。 |
exception-handler | 要素 | [0..*] | プロセスノードから委譲クラスによってスローされたすべての例外に適用される例外ハンドラのリスト |
14.4.16. action
表14.16 アクションスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | アクションの名前。アクションに名前が指定されている場合はプロセス定義から名前を検索できます。これは実行時アクションとアクションを一度だけ宣言する場合に便利です。 |
class | 属性 | 参照名または式のいずれか | org.jbpm.graph.def.ActionHandler インターフェースを実装するクラスの完全修飾クラス名 |
ref-name | 属性 | this または class | 参照されたアクション名。参照アクションが指定された場合はこのアクションの内容が処理されません。 |
expression | 属性 | this、class、ref-nameのいづれか | メソッドを解決するjPDL表現。 「式」 も参照してください。 |
accept-propagated-events | 属性 | 任意 | オプションは {yes|no|true|false} です。 デフォルト値は yes|true です。false に設定された場合、 アクションはこのアクションの要素でトリガーされたイベントでのみ実行されます。 詳細については、「イベントを渡す」 を参照してください。 |
config-type | 属性 | 任意 | {field|bean|constructor|configuration-property} 。 action-object の構築方法やこの要素の内容を action-object の設定情報として使用する方法を指定します。 |
async | 属性 | {true|false} | 'async="true" は、 イベントでトリガーされた場合のみ action でサポートされます。 デフォルト値はfalse であり、 action は実行スレッドで実行されます。 true に設定された場合は、 コマンドエグゼキューターにメッセージが送信され、 そのコンポーネントが別のトランザクションで非同期でアクションを実行します。 |
{content} | 任意 | アクションの内容は、カスタムアクション実装の設定情報として使用できます。 これにより、 再利用可能な委譲クラスを作成できます。 委譲設定の詳細については、「委譲設定」 を参照してください。 |
14.4.17. script
表14.17 スクリプトスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | script-actionの名前。アクションに名前が指定されている場合は、名前をプロセス定義から検索できます。これは、ランタイム時アクションの場合やアクションを一度だけ宣言する場合に便利です。 |
accept-propagated-events | 属性 | optional [0..*] | {yes|no|true|false}。 デフォルト値は yes|true です。false に設定された場合、 アクションはこのアクションの要素でトリガされたイベントでのみ実行されます。 詳細については、「イベントを渡す」 を参照してください。 |
expression | 要素 | [0..1] |
bean-shell スクリプト。変数要素を指定しないと、スクリプト要素の内容として表現を記述できます (表現エレメントタグは省略)。変数および/あるいは表現要素とあわせて「スクリプト要素の内容として表現」を利用する場合、スクリプト要素の内容は無視されます。
public void read(Element scriptElement, JpdlXmlReader jpdlReader) { if (scriptElement.isTextOnly()) { expression = scriptElement.getText(); } else { this.variableAccesses = new HashSet(jpdlReader.readVariableAccesses(scriptElement)); expression = scriptElement.element("expression").getText(); } } |
variable | 要素 | [0..*] | スクリプトの変数。in変数が指定されていない場合は現在のトークンのすべての変数がスクリプト評価にロードされます。スクリプト評価にロードする変数の数を制限する場合は、in変数を使用します。 |
14.4.18. expression
表14.18 表現スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
{content} | Bean シェルスクリプト |
14.4.19. variable
表14.19 変数スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 必須 | プロセス変数名 |
access | 属性 | 任意 | デフォルト値は read,write です。 これはアクセス指定子のコンマ区切りリストです。 これまで使用されたアクセス指定子は read 、write 、required のみです。 「required」はタスク変数をプロセス変数に送信する場合のみ適切です。 |
mapped-name | 属性 | 任意 | デフォルトでは変数名に設定されます。変数名がマップされた名前を指定します。mapped-nameの意味はこの要素が使用されるコンテキストに依存します。スクリプトの場合はscript-variable-nameになります。タスクコントローラの場合はタスクフォームパラメータのラベルになり、process-stateの場合はsub-processで使用された変数名になります。 |
14.4.20. handler
表14.20 ハンドラスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
expression | 属性 | this または class | JPDL 式。返された結果は toString() メソッドにより文字列に変換されます。変換された文字列は退場遷移のいずれかに一致します。 「式」 も参照してください。 |
class | 属性 | thisまたはref-name | org.jbpm.graph.node.DecisionHandler インターフェースを実装するクラスの完全修飾クラス名 |
config-type | 属性 | 任意 | {field|bean|constructor|configuration-property}。 action-object の構築方法やこのエレメントの内容を action-object の設定情報として使用する方法を指定します。 |
{content} | 任意 | ハンドラの内容はカスタムハンドラ実装の設定情報として使用できます。 これにより、再利用可能な移譲クラスを作成できます。移譲設定の詳細については、 「委譲設定」を参照してください。 |
14.4.21. timer
表14.21 タイマースキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | タイマーの名前。名前を指定しない場合は、閉じるノードの名前が取得されます。各タイマーは一意の名前を持つことに注意してください。 |
duedate | 属性 | 必須 | タイマーの作成からタイマーの実行までの時間 (営業時間で示すこともできます)。 構文については 「Duration (期間)」 を参照してください。 |
repeat | 属性 | 任意 | {duration | 'yes' | 'true'}。 タイマーが期日に実行された後は、'repeat' はノードが退場するまでの繰り返しでタイマーを実行する間隔をオプションで指定します。yes または true が指定された場合は、 repeat に期日と同じ期間が使用されます。構文については、「Duration (期間)」 を参照してください。 |
transition | 属性 | 任意 | タイマーイベントが発生しアクションを実行した後にタイマーが実行されたときに取得されるtransition-name |
cancel-event | 属性 | 任意 | この属性はタスクのタイマーでのみ使用されます。 タイマーをキャンセルするイベントを指定します。 デフォルトは、task-end イベントですが、task-assign や task-start を設定することもできます。 属性にてカンマ区切りリストを指定すると、cancel-event タイプを組み合わせることができます。 |
{action|script|create-timer|cancel-timer} | 要素 | [0..1] | このタイマーが起動したときに実行されるアクション |
14.4.22. create-timer
表14.22 Create Timer スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | タイマーの名前。 この名前は cancel-timer アクションでタイマーをキャンセルするのに使用できます。 |
duedate | 属性 | 必須 | タイマーの作成からタイマーの実行までの時間 (営業時間で示すこともできます)。 構文については 「Duration (期間)」 を参照してください。 |
repeat | 属性 | 任意 | {duration | 'yes' | 'true'}。 タイマーが期日に実行された後は、'repeat' はノードが退場するまでの繰り返しでタイマーを実行する間隔をオプションで指定します。yes または true が指定された場合は、repeat に期日と同じ期間が使用されます。構文については、「Duration (期間)」 を参照してください。 |
transition | 属性 | 任意 | タイマーイベントが発生し、アクションを実行した後にタイマーが実行されたときに取得するtransition-name |
14.4.23. cancel-timer
表14.23 Cancel Timer スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | キャンセルされるタイマーの名前。 |
14.4.24. task
表14.24 タスクスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 任意 | タスクの名前。名前が付けられたタスクは、TaskMgmtDefinition によって参照および検索できます。 |
blocking | 属性 | 任意 | {yes|no|true|false}、デフォルトはfalseです。 もしtrueにセットされた場合、タスクが終了していない際にはノードを退場することはできません。 もしfalse (デフォルト) でセットされた場合、 トークンのシグナルは実行を続行し、ノードを退場することができます。 blockingは普通、ユーザインターフェースによって 行われるものなのでデフォルトとしてfalseにしています。 |
signalling | 属性 | 任意 | {yes|no|true|false}、デフォルトは true です。シグナリングが false に設定されている場合は、このタスクはトークンの続行をトリガーする機能を持ちません。 |
duedate | 属性 | 任意 | 11章ビジネスカレンダー で説明された絶対または営業時間で示された期間。 |
swimlane | 属性 | 任意 | スイムレーンの参照。 タスクにスイムレーンを指定した場合、割り当ては無視されます。 |
priority | 属性 | 任意 | {highest, high, normal, low, lowest}のいずれか。または、優先順位として整数を指定できます(最大=1、最小=5)。 |
assignment | 要素 | 任意 | タスクが作成された時に、 アクターにタスクを割り当てる委譲を記述します。 |
event | 要素 | [0..*] | サポートされているイベントタイプは{task-create|task-start|task-assign|task-end}。task-assign に対して特別に非永続化プロパティpreviousActorId をTaskInstance に追加しました。 |
exception-handler | 要素 | [0..*] | プロセスノードでスローされた移譲クラスによってスローされたすべての例外に適用される例外ハンドラのリスト |
timer | 要素 | [0..*] | このタスクで実行の継続時間を監視するタイマーを指定します。タスクタイマーに対して特別にcancel-event を指定できます。デフォルトでは、cancel-event はtask-end ですが、task-assign やtask-start などにカスタマイズできます。 |
controller | 要素 | [0..1] | プロセス変数をどのようにタスクフォームパラメーターに変換するかを指定します。タスクフォームパラメーターはタスクフォームをユーザーにレンダリングするためにユーザーインターフェースによって使用されます。 |
14.4.25. スイムレーン
表14.25 スイムレーンスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 必須 | スイムレーンの名前。スイムレーンはTaskMgmtDefinition を使用して参照および検索できます。 |
assignment | 要素 | [1..1] | スイムレーンの割り当てを指定します。割り当ては、このスイムレーンで最初のタスクインスタンスが作成されたときに実行されます。 |
14.4.26. 割り当て
表14.26 割り当てスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
expression | 属性 | 任意 | 歴史的な経緯から、 この属性表現は JPDL 式を参照しません。ただし、JBPM アイデンティティコンポーネントの割り当て表現となります。JBPM アイデンティティコンポーネント表現の記述方法の詳細については、「割り当て式」 を参照してください。この実装は jbpm アイデンティティコンポーネントの依存関係を持つことに注意してください。 |
actor-id | 属性 | 任意 | actorId。 pooled-actors と組み合わせて使用できます。 actor-id は表現として解決されます。 したがって、 actor-id="bobthebuilder" のような固定actorId を参照できます。 または、 タスクインスタンス変数 "myVar" で getActorId メソッドを呼び出す actor-id="myVar.actorId" のような文字列を返すプロパティまたはメソッドを参照できます。 |
pooled-actors | 属性 | 任意 | コンマ区切りのactorId のリスト。 actor-id と組み合わせて使用できます。 固定のプールactorId のセットは pooled-actors="chicagobulls, pointersisters" のように指定することができます。 pooled-actors は、 表現として解決されます。 そのため、 String[]、 コレクション、 プールアクター のコンマ区切りのリストを返さなければならないプロパティやメソッドも参照できます。 |
class | 属性 | 任意 | org.jbpm.taskmgmt.def.AssignmentHandler 実装の完全修飾クラス名 |
config-type | 属性 | 任意 | {field|bean|constructor|configuration-property}。 assignment-handler-object の構築方法やこのエレメントの内容を assignment-handler-object の設定情報として使用する方法を指定します。 |
{content} | 任意 | assignment-element の内容は AssignmentHandler 実装の設定情報として使用できます。 これにより、 再利用可能な委譲クラスを作成できます。 委譲設定の詳細については、 「委譲設定」 を参照してください。 |
14.4.27. Controller
表14.27 コントローラスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
class | 属性 | 任意 | org.jbpm.taskmgmt.def.TaskControllerHandler 実装の完全修飾クラス名 |
config-type | 属性 | 任意 | {field|bean|constructor|configuration-property}。 assignment-handler-object の構築方法やこの要素の内容を assignment-handler-object の設定情報として使用する方法を指定します。 |
{content} | どちらの場合もコントローラーの内容は指定されたタスクコントローラーハンドラーの設定になります(クラス属性が指定されている場合)。タスクコントーラハンドラーが指定されていない場合は、内容をvariable要素のリストにしなければなりません。 | ||
variable | 要素 | [0..*] | タスクコントローラーがクラス属性によって指定されていない場合、controller要素の内容は変数のリストである必要があります。 |
14.4.28. sub-process
表14.28 サブプロセススキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
name | 属性 | 必須 | 呼び出す sub-process の名前。EL 式を使用できますが、String との検証が必要があります。 |
version | 属性 | 任意 | 呼び出す sub-process のバージョン。version が指定されない場合、 process-state は指定プロセスの最新版を使用します。 |
binding | 属性 | 任意 | Sub-process が解決されるタイミングを定義します。オプションは{early|late} 。デフォルトは、解決は early でデプロイメント時に行う設定です。binding が late として定義されている場合、process-state は各実行時に指定プロセスの最新版を解決します。Late バインディングは、固定のバージョンとの組み合わせでは意味がないため、binding="late" の場合は version 属性は無視されます。 |
14.4.29. condition
表14.29 条件スキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
このオプションは{content} で、後方互換性を保証するために、expression属性では条件を入力することもできます。ただし、この属性はバージョン3.2で削除されています。 | 必須 | condition 要素の内容は Boolean を評価する JPDL 表現です。表現が true に解決された最初の遷移 (processdefinition.xml の順番通り) を取ります。true に解決される条件がない場合、デフォルトの退場遷移 (最初のもの) が取得されます。 |
14.4.30. exception-handler
表14.30 例外ハンドラスキーマ
名前 | 種類 | 多重度 | 説明 |
---|---|---|---|
exception-class | 属性 | 任意 | これは、Java の「スロー可能な」クラスの完全修飾名を指定しており、この例外ハンドラと一致するはずです。 この属性が指定されないと、 すべての例外 (java.lang.Throwable ) に一致します。 |
action | 要素 | [1..*] | この例外ハンドラーによってエラー処理されるときに実行するアクションのリスト |
第15章 Workflow のテスト駆動開発 (TDD)
15.1. Workflow のテスト駆動開発の紹介

図15.1 オークションテストプロセス
public class AuctionTest extends TestCase { // parse the process definition static ProcessDefinition auctionProcess = ProcessDefinition.parseParResource("org/jbpm/tdd/auction.par"); // get the nodes for easy asserting static StartState start = auctionProcess.getStartState(); static State auction = (State) auctionProcess.getNode("auction"); static EndState end = (EndState) auctionProcess.getNode("end"); // the process instance ProcessInstance processInstance; // the main path of execution Token token; public void setUp() { // create a new process instance for the given process definition processInstance = new ProcessInstance(auctionProcess); // the main path of execution is the root token token = processInstance.getRootToken(); } public void testMainScenario() { // after process instance creation, the main path of // execution is positioned in the start state. assertSame(start, token.getNode()); token.signal(); // after the signal, the main path of execution has // moved to the auction state assertSame(auction, token.getNode()); token.signal(); // after the signal, the main path of execution has // moved to the end state and the process has ended assertSame(end, token.getNode()); assertTrue(processInstance.hasEnded()); } }
15.2. XMLソース
ProcessDefinition
を作成する必要があります。 ProcessDefinition
オブジェクトを取得する最も簡単な方法は、XML を構文解析することです。 ProcessDefinition.parse
とタイプして、 コード補完機能を起動させてください。 構文解析を行うさまざまなメソッドが表示されます。ProcessDefinition
オブジェクトに構文解析可能な基本的記述方法は 3 つあります。
15.2.1. プロセスアーカイブの構文解析
processdefinition.xml
というプロセスの XML ファイルが含まれている zip ファイルです。JBPM プロセスデザイナープラグインはプロセスアーカイブを読み書きします。
static ProcessDefinition auctionProcess = ProcessDefinition.parseParResource("org/jbpm/tdd/auction.par");
15.2.2. XML ファイルの構文解析
processdefinition.xml
ファイルを記述する場合JpdlXmlReader
を利用し、ant
スクリプトを使い、できたZIPファイルをパッケージします。
static ProcessDefinition auctionProcess = ProcessDefinition.parseXmlResource("org/jbpm/tdd/auction.xml");
15.2.3. XML String の構文解析
static ProcessDefinition auctionProcess = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state name='start'>" + " <transition to='auction'/>" + " </start-state>" + " <state name='auction'>" + " <transition to='end'/>" + " </state>" + " <end-state name='end'/>" + "</process-definition>");
付録A GNU Lesser General Public License 2.1
GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it!
付録B 改訂履歴
改訂履歴 | |||
---|---|---|---|
改訂 5.2.0-1.402 | Fri Oct 25 2013 | ||
| |||
改訂 5.2.0-1.33 | 2012-07-25 | ||
| |||
改訂 5.2.0-0 | Wed Jun 29 2011 | ||
| |||
改訂 5.1.0-0 | Fri Feb 18 2011 | ||
| |||
改訂 5.0.2-0 | Wed May 26 2010 | ||
| |||
改訂 5.0.1-0 | Tue Apr 20 2010 | ||
| |||
改訂 5.0.0-0 | Sat Jan 30 2010 | ||
|