68.4. EJB との統合

プロセスエンジンは、Enterprise Java Bean (EJB) の完全な統合レイヤーを提供します。このレイヤーは、ローカルおよびリモートの EJB 対話の両方をサポートします。

以下のモジュールは EJB サービスを提供します。

  • jbpm-services-ejb-api: jbpm-services-api モジュールを EJB 固有のインターフェイスおよびオブジェクトで拡張する API モジュール
  • jbpm-services-ejb-impl: コアサービスの EJB 拡張
  • jbpm-services-ejb-timer: EJB Timer サービスに基づくプロセスエンジンスケジューラーサービスの実装
  • jbpm-services-ejb-client: デフォルトでは Red Hat JBoss EAP をサポートするリモート対話の EJB リモートクライアント実装

EJB レイヤーはプロセスエンジンサービスに基づいています。リモートインターフェイスを使用する場合はいくつかの制限がありますが、コアモジュールとほぼ同じ機能を提供します。

デプロイメントサービスの主な制限は、リモート EJB サービスとして使用されている場合に、以下の方法のみをサポートします。

  • deploy()
  • undeploy()
  • activate()
  • deactivate()
  • isDeployed()

他のメソッドは、リモートインターフェイスに使用できない RuntimeManager などのランタイムオブジェクトのインスタンスを返すため除外されます。

他のすべてのサービスは、コアモジュールに含まれているバージョンと同じ機能を EJB 上で提供します。

68.4.1. EJB サービスの実装

プロセスエンジンのコアサービスの拡張として、EJB サービスは EJB ベースの実行セマンティクスを提供し、さまざまな EJB 固有の機能をベースにしています。

  • DeploymentServiceEJBImpl は、コンテナー管理の同時実行性を備えた EJB シングルトンとして実装されます。ロックタイプは write に設定されます。
  • DefinitionServiceEJBImpl は、コンテナー管理の同時実行性を備えた EJB シングルトンとして実装されます。この全体的なロックタイプは read に設定されます。buildProcessDefinition() メソッドの場合は ロックタイプが write に設定されます。
  • ProcessServiceEJBImpl は、ステートレスセッション Bean として実装されます。
  • RuntimeDataServiceEJBImpl は、EJB シングルトンとして実装されます。ほとんどのメソッドでは、ロックタイプが read に設定されます。以下のメソッドでは、ロックタイプが write に設定されます。

    • onDeploy()
    • onUnDeploy()
    • onActivate()
    • onDeactivate()
  • UserTaskServiceEJBImpl は、ステートレスセッション Bean として実装されます。

トランザクション

EJB コンテナーは EJB サービスでトランザクションを管理します。このため、アプリケーションコード内でトランザクションマネージャーまたはユーザートランザクションを設定する必要はありません。

アイデンティティープロバイダー

デフォルトのアイデンティティープロバイダーは EJBContext インターフェイスをベースとし、名前とロールの両方に呼び出し元プリンシパル情報に依存します。IdentityProvider インターフェイスは、ロールに関連する 2 つのメソッドを提供します。

  • EJBContext インターフェイスは特定ユーザーの全ロールを取得するオプションを提供しないため、getRoles() によって空のリストが返されます。
  • hasRole() はコンテキストの isCallerInRole() メソッドに委譲されます。

EJB 環境で有効な情報を利用できるようにするには、標準の JEE セキュリティープラクティスに従ってユーザーを認証および承認する必要があります。EJB サービスに認証または承認が設定されていない場合、匿名ユーザーは常に仮定されます。

別のセキュリティーモデルを使用する場合は、EJB サービスの IdentityProvider オブジェクトに CDI 形式の挿入を使用できます。この場合は、org.kie.internal.identity.IdentityProvider インターフェイスを実装する有効な CDI Bean を作成し、アプリケーションでの挿入でこの Bean を利用できるようにします。この実装は、EJBContext ベースのアイデンティティープロバイダーよりも優先されます。

デプロイメントの同期

デプロイメントの同期はデフォルトで有効になり、3 秒ごとにすべてのデプロイメントの同期を試みます。コンテナー管理コンカレンシーを使用する EJB シングルトンとして実装されます。ロックタイプは write に設定されます。EJB タイマーサービスを使用して同期ジョブをスケジュールします。

EJB スケジューラーサービス

プロセスエンジンは、スケジューラーサービスを使用してタイマーイベントやデッドラインなどの時間ベースのアクティビティーを処理します。EJB 環境で実行する場合、プロセスエンジンは EJB タイマーサービスに基づいてスケジューラーを使用します。すべての RuntimeManager インスタンスに対してこのスケジューラーを登録します。

クラスター操作に対応するためにアプリケーションサーバーに固有の設定を使用しないといけない場合があります。

UserGroupCallback および UserInfo 実装の選択

UserGroupCallback インターフェイスおよび UserInfo インターフェイスに必要な実装は、さまざまなアプリケーションで異なる場合があります。これらのインターフェイスに EJB を直接挿入することはできません。以下のシステムプロパティーを使用して、既存の実装を選択するか、プロセスエンジンにこれらのインターフェイスのカスタム実装を使用できます。

  • org.jbpm.ht.callback: このプロパティーは、UserGroupCallback インターフェイスの実装を選択します。

    • mvel: 通常、テストに使用するデフォルトの実装です。
    • ldap: LDAP ベースの実装。この実装には、jbpm.usergroup.callback.properties ファイルで追加の設定が必要です。
    • db: データベースベースの実装。この実装には、jbpm.usergroup.callback.properties ファイルで追加の設定が必要です。
    • jaas: コンテナーからユーザー情報を要求する実装。
    • props: 単純なプロパティーベースのコールバック。この実装には、ユーザーおよびグループすべてが含まれる追加のプロパティーファイルが必要です。
    • custom: カスタム実装。実装の完全修飾クラス名を org.jbpm.ht.custom.callback システムプロパティーに指定する必要があります。
  • org.jbpm.ht.userinfo: このプロパティーは UserInfo インターフェイスの実装を選択します。

    • ldap: LDAP ベースの実装。この実装には、jbpm-user.info.properties ファイルで追加の設定が必要です。
    • db: データベースベースの実装。この実装には、jbpm-user.info.properties ファイルで追加の設定が必要です。
    • props: 単純なプロパティーベースの実装。この実装には、すべてのユーザー情報が含まれる追加のプロパティーファイルが必要です。
    • custom: カスタム実装。実装の完全修飾クラス名を org.jbpm.ht.custom.userinfo システムプロパティーに指定する必要があります。

通常、アプリケーションサーバーまたは JVM の起動時にシステムプロパティーを設定します。サービスを使用する前に、コードでプロパティーを設定することもできます。たとえば、これらのシステムプロパティーを設定するカスタムの @Startup Bean を指定できます。

68.4.2. ローカル EJB インターフェイス

以下のローカル EJB サービスインターフェイスはコアサービスを拡張します。

  • org.jbpm.services.ejb.api.DefinitionServiceEJBLocal
  • org.jbpm.services.ejb.api.DeploymentServiceEJBLocal
  • org.jbpm.services.ejb.api.ProcessServiceEJBLocal
  • org.jbpm.services.ejb.api.RuntimeDataServiceEJBLocal
  • org.jbpm.services.ejb.api.UserTaskServiceEJBLocal

これらのインターフェイスを挿入ポイントとして使用し、@EJB アノテーションを付ける必要があります。

ローカルの EJB サービスインターフェイスの使用

@EJB
private DefinitionServiceEJBLocal bpmn2Service;

@EJB
private DeploymentServiceEJBLocal deploymentService;

@EJB
private ProcessServiceEJBLocal processService;

@EJB
private RuntimeDataServiceEJBLocal runtimeDataService;

これらのインターフェイスを挿入した後に、コアモジュールと同じ方法で操作を呼び出します。ローカルインターフェイスの使用には制限がありません。

68.4.3. リモート EJB インターフェイス

以下の専用のリモート EJB インターフェイスはコアサービスを拡張します。

  • org.jbpm.services.ejb.api.DefinitionServiceEJBRemote
  • org.jbpm.services.ejb.api.DeploymentServiceEJBRemote
  • org.jbpm.services.ejb.api.ProcessServiceEJBRemote
  • org.jbpm.services.ejb.api.RuntimeDataServiceEJBRemote
  • org.jbpm.services.ejb.api.UserTaskServiceEJBRemote

これらのインターフェイスは、カスタムタイプの処理を除き、ローカルインターフェイスと同じ方法で使用できます。

カスタムタイプは 2 つの方法で定義できます。グローバル に定義されたタイプは、アプリケーションクラスパスで利用でき、エンタープライズアプリケーションに含まれます。ローカルでデプロイメントユニット にタイプを定義する場合、タイプはプロジェクトの依存関係 (KJAR ファイルなど) で宣言され、デプロイメント時に解決されます。

グローバルで利用可能なタイプには、特別な処理は必要ありません。EJB コンテナーは、リモートリクエストの処理時にデータを自動的にマーシャルします。ただし、ローカルカスタムタイプは、デフォルトでは EJB コンテナーに表示されません。

プロセスエンジン EJB サービスは、カスタムタイプと連携するメカニズムを提供します。他にも、以下の 2 つのタイプが提供されます。

  • org.jbpm.services.ejb.remote.api.RemoteObject: シングル値パラメーターのシリアライズ可能なラッパークラス
  • org.jbpm.services.ejb.remote.api.RemoteMap: カスタムオブジェクト入力を受け入れるサービスメソッドのリモート呼び出しを単純化する専用の java.util.Map 実装。マップの内部実装は、送信時に追加のシリアライズを回避するために、すでにシリアライズされているコンテンツを保持します。

    この実装には、通常データ送信時には使用されない java.util.Map のメソッドが含まれません。

これらの特別なオブジェクトは、ObjectInputStream オブジェクトを使用してバイトに対してシリアライズを実行します。EJB クライアント/コンテナーでのデータのシリアライズに必要なものを削除します。シリアライズは必要ないため、カスタムデータモデルを EJB コンテナーと共有する必要はありません。

以下のコード例は、ローカルタイプおよびリモート EJB サービスと動作します。

リモート EJB サービスでのローカルタイプの使用

// Start a process with custom types via remote EJB

Map<String, Object> parameters = new RemoteMap();
Person person = new org.jbpm.test.Person("john", 25, true);
parameters.put("person", person);

Long processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "custom-data-project.work-on-custom-data", parameters);

// Fetch task data and complete a task with custom types via remote EJB
Map<String, Object> data = userTaskService.getTaskInputContentByTaskId(taskId);

Person fromTaskPerson = data.get("_person");
fromTaskPerson.setName("John Doe");

RemoteMap outcome = new RemoteMap();
outcome.put("person_", fromTaskPerson);

userTaskService.complete(taskId, "john", outcome);

同様に、RemoteObject クラスを使用してイベントをプロセスインスタンスに送信できます。

// Send an event with a custom type via remote EJB
Person person = new org.jbpm.test.Person("john", 25, true);

RemoteObject myObject = new RemoteObject(person);

processService.signalProcessInstance(processInstanceId, "MySignal", myObject);

68.4.4. リモート EJB クライアント

リモートクライアントサポートは、アプリケーションサーバー固有のコード向けのファサードである ClientServiceFactory インターフェイスの実装によって提供されます。

ClientServiceFactory インターフェイスの定義

/**
 * Generic service factory used for remote lookups that are usually container specific.
 *
 */
public interface ClientServiceFactory {

	/**
	 * Returns unique name of given factory implementation
	 * @return
	 */
	String getName();

	/**
	 * Returns remote view of given service interface from selected application
	 * @param application application identifier on the container
	 * @param serviceInterface remote service interface to be found
	 * @return
	 * @throws NamingException
	 */
	<T> T getService(String application, Class<T> serviceInterface) throws NamingException;
}

ServiceLoader メカニズムを使用して実装を動的に登録できます。デフォルトでは、Red Hat JBoss EAP で利用可能な実装は 1 つだけです。

ClientServiceFactory 実装は名前を指定する必要があります。この名前は、クライアントレジストリー内で登録するために使用されます。名前で実装を検索できます。

以下のコードは、デフォルトの Red Hat JBoss EAP リモートクライアントを取得します。

デフォルトの Red Hat JBoss EAP リモートクライアントの取得

// Retrieve a valid client service factory
ClientServiceFactory factory = ServiceFactoryProvider.getProvider("JBoss");

// Set the application variable to the module name
String application = "sample-war-ejb-app";

// Retrieve the required service from the factory
DeploymentServiceEJBRemote deploymentService = factory.getService(application, DeploymentServiceEJBRemote.class);

サービスを取得したら、そのメソッドを使用できます。

Red Hat JBoss EAP とリモートクライアントを使用する際に、以下の Maven 依存関係を追加して、すべての EJB クライアントライブラリーを取り込むことができます。

<dependency>
  <groupId>org.jboss.as</groupId>
  <artifactId>jboss-as-ejb-client-bom</artifactId>
  <version>7.3.0.Final</version> <!-- use the valid version for the server you run on -->
  <optional>true</optional>
  <type>pom</type>
</dependency>