16.2. カスタムデータトランスポートを使用するための Decision Server の拡張
デフォルトでは、Decision Server の拡張が REST または JMS データトランスポートを使用して公開されます。Decision Server を拡張して、カスタムのデータトランスポートのサポートを追加し、Decision Server トランスポートプロトコルをビジネスニーズに適合します。
たとえば、以下の手順では、Drools
拡張を使用し、Apache MINA (オープンソースの Java ネットワークアプリケーションフレームワーク) をベースとする Decision Server にカスタムのデータトランスポートを追加します。カスタムの MINA トランスポートの例では、既存のマーシャリング操作に依存し、JSON 形式のみをサポートする文字列ベースのデータを変換します。
手順
空の Maven プロジェクトを作成して、以下のパッケージタイプと依存関係を、プロジェクトの
pom.xml
ファイルに定義します。サンプルプロジェクトの pom.xml ファイルの例
<packaging>jar</packaging> <properties> <version.org.kie>7.14.0.Final-redhat-00002</version.org.kie> </properties> <dependencies> <dependency> <groupId>org.kie</groupId> <artifactId>kie-api</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.kie</groupId> <artifactId>kie-internal</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.kie.server</groupId> <artifactId>kie-server-api</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.kie.server</groupId> <artifactId>kie-server-services-common</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.kie.server</groupId> <artifactId>kie-server-services-drools</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>${version.org.kie}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.apache.mina</groupId> <artifactId>mina-core</artifactId> <version>2.1.3</version> </dependency> </dependencies>
以下の例のように、プロジェクトの Java クラスに
org.kie.server.services.api.KieServerExtension
インターフェイスを実装します。KieServerExtension
インターフェイスの実装例public class MinaDroolsKieServerExtension implements KieServerExtension { private static final Logger logger = LoggerFactory.getLogger(MinaDroolsKieServerExtension.class); public static final String EXTENSION_NAME = "Drools-Mina"; private static final Boolean disabled = Boolean.parseBoolean(System.getProperty("org.kie.server.drools-mina.ext.disabled", "false")); private static final String MINA_HOST = System.getProperty("org.kie.server.drools-mina.ext.port", "localhost"); private static final int MINA_PORT = Integer.parseInt(System.getProperty("org.kie.server.drools-mina.ext.port", "9123")); // Taken from dependency on the `Drools` extension: private KieContainerCommandService batchCommandService; // Specific to MINA: private IoAcceptor acceptor; public boolean isActive() { return disabled == false; } public void init(KieServerImpl kieServer, KieServerRegistry registry) { KieServerExtension droolsExtension = registry.getServerExtension("Drools"); if (droolsExtension == null) { logger.warn("No Drools extension available, quiting..."); return; } List<Object> droolsServices = droolsExtension.getServices(); for( Object object : droolsServices ) { // If the given service is null (not configured), continue to the next service: if (object == null) { continue; } if( KieContainerCommandService.class.isAssignableFrom(object.getClass()) ) { batchCommandService = (KieContainerCommandService) object; continue; } } if (batchCommandService != null) { acceptor = new NioSocketAcceptor(); acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" )))); acceptor.setHandler( new TextBasedIoHandlerAdapter(batchCommandService) ); acceptor.getSessionConfig().setReadBufferSize( 2048 ); acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 ); try { acceptor.bind( new InetSocketAddress(MINA_HOST, MINA_PORT) ); logger.info("{} -- Mina server started at {} and port {}", toString(), MINA_HOST, MINA_PORT); } catch (IOException e) { logger.error("Unable to start Mina acceptor due to {}", e.getMessage(), e); } } } public void destroy(KieServerImpl kieServer, KieServerRegistry registry) { if (acceptor != null) { acceptor.dispose(); acceptor = null; } logger.info("{} -- Mina server stopped", toString()); } public void createContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) { // Empty, already handled by the `Drools` extension } public void disposeContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) { // Empty, already handled by the `Drools` extension } public List<Object> getAppComponents(SupportedTransports type) { // Nothing for supported transports (REST or JMS) return Collections.emptyList(); } public <T> T getAppComponents(Class<T> serviceType) { return null; } public String getImplementedCapability() { return "BRM-Mina"; } public List<Object> getServices() { return Collections.emptyList(); } public String getExtensionName() { return EXTENSION_NAME; } public Integer getStartOrder() { return 20; } @Override public String toString() { return EXTENSION_NAME + " KIE Server extension"; } }
KieServerExtension
インターフェイスは、新規の MINA トランスポートの機能を追加する時に Decision Server が使用する主要な拡張インターフェイスです。このインターフェイスには、以下のコンポーネントが含まれます。KieServerExtension
インターフェイスの概要public interface KieServerExtension { boolean isActive(); void init(KieServerImpl kieServer, KieServerRegistry registry); void destroy(KieServerImpl kieServer, KieServerRegistry registry); void createContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters); void disposeContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters); List<Object> getAppComponents(SupportedTransports type); <T> T getAppComponents(Class<T> serviceType); String getImplementedCapability(); 1 List<Object> getServices(); String getExtensionName(); 2 Integer getStartOrder(); 3 }
このインターフェイスの先程の
MinaDroolsKieServerExtension
実装例では、init
メソッドが主に、Drools
拡張からサービスを収集して、MINA サーバーをブートストラップ化する要素となっています。KieServerExtension
インターフェイスの他のメソッドは、標準の実装のままで、インターフェイスの要件を満たします。TextBasedIoHandlerAdapter
クラスは、受信要求に対応する MINA サーバーにあるハンドラーです。以下の例のように、MINA サーバーの
TextBasedIoHandlerAdapter
ハンドラーを実装します。TextBasedIoHandlerAdapter
ハンドラーの実装例public class TextBasedIoHandlerAdapter extends IoHandlerAdapter { private static final Logger logger = LoggerFactory.getLogger(TextBasedIoHandlerAdapter.class); private KieContainerCommandService batchCommandService; public TextBasedIoHandlerAdapter(KieContainerCommandService batchCommandService) { this.batchCommandService = batchCommandService; } @Override public void messageReceived( IoSession session, Object message ) throws Exception { String completeMessage = message.toString(); logger.debug("Received message '{}'", completeMessage); if( completeMessage.trim().equalsIgnoreCase("quit") || completeMessage.trim().equalsIgnoreCase("exit") ) { session.close(false); return; } String[] elements = completeMessage.split("\\|"); logger.debug("Container id {}", elements[0]); try { ServiceResponse<String> result = batchCommandService.callContainer(elements[0], elements[1], MarshallingFormat.JSON, null); if (result.getType().equals(ServiceResponse.ResponseType.SUCCESS)) { session.write(result.getResult()); logger.debug("Successful message written with content '{}'", result.getResult()); } else { session.write(result.getMsg()); logger.debug("Failure message written with content '{}'", result.getMsg()); } } catch (Exception e) { } } }
この例では、ハンドラークラスはテキストメッセージを受信して、
Drools
サービスでこのメッセージを実行します。TextBasedIoHandlerAdapter
ハンドラー実装を使用する場合は、以下のハンドラー要件と動作を考慮してください。- 各受信トランスポート要求が 1 行であるため、ハンドラーに送信する内容は、1 行でなければなりません。
-
ハンドラーで
containerID|payload
の形式が想定されるように、この 1 行に KIE コンテナー ID を渡す必要があります。 - マーシャラーで生成される方法で応答を設定できます。応答は複数行にすることができます。
-
このハンドラーは stream mode をサポートし、Decision Server セッションを切断せずにコマンドを送信できます。ストリームモードで Decision Server セッションを終了するには、サーバーに
exit
またはquit
コマンドを送信してください。
-
新規のデータトランスポートを Decision Server で検出できるようにするには、Maven プロジェクトで
META-INF/services/org.kie.server.services.api.KieServerExtension
ファイルを作成し、このファイルにKieServerExtension
実装クラスの完全修飾名を追加します。たとえば、このファイルにはorg.kie.server.ext.mina.MinaDroolsKieServerExtension
の 1 行が含まれます。 -
プロジェクトを構築して、作成された JAR ファイルと
mina-core-2.0.9.jar
ファイル (今回の例でこの拡張が依存) をプロジェクトの~/kie-server.war/WEB-INF/lib
ディレクトリーにコピーします。たとえば、Red Hat JBoss EAP ではこのディレクトリーへのパスはEAP_HOME/standalone/deployments/kie-server.war/WEB-INF/lib
です。 Decision Server を起動して、実行中の Decision Server に構築したプロジェクトをデプロイします。プロジェクトは、Decision Central インターフェイスまたは Decision Server REST API (
http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId}
へのPUT
要求) のいずれかを使用してデプロイできます。プロジェクトを実行中の Decision Server にデプロイした後に、Decision Server ログで新規データトランスポートのステータスを表示して、新規データトランスポートの使用を開始できます。
サーバーログの新規データトランスポート
Drools-Mina KIE Server extension -- Mina server started at localhost and port 9123 Drools-Mina KIE Server extension has been successfully registered as server extension
この例では、Telnet を使用して Decision Server の 新しい MINA ベースのデータトランスポートと対話できます。
コマンドターミナルでの Telnet の開始およびポート 9123 での Decision Server の接続
telnet 127.0.0.1 9123
コマンドターミナルでの Decision Server との対話例
Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. # Request body: demo|{"lookup":"defaultKieSession","commands":[{"insert":{"object":{"org.jbpm.test.Person":{"name":"john","age":25}}}},{"fire-all-rules":""}]} # Server response: { "results" : [ { "key" : "", "value" : 1 } ], "facts" : [ ] } demo|{"lookup":"defaultKieSession","commands":[{"insert":{"object":{"org.jbpm.test.Person":{"name":"mary","age":22}}}},{"fire-all-rules":""}]} { "results" : [ { "key" : "", "value" : 1 } ], "facts" : [ ] } demo|{"lookup":"defaultKieSession","commands":[{"insert":{"object":{"org.jbpm.test.Person":{"name":"james","age":25}}}},{"fire-all-rules":""}]} { "results" : [ { "key" : "", "value" : 1 } ], "facts" : [ ] } exit Connection closed by foreign host.
サーバーログの出力例
16:33:40,206 INFO [stdout] (NioProcessor-2) Hello john 16:34:03,877 INFO [stdout] (NioProcessor-2) Hello mary 16:34:19,800 INFO [stdout] (NioProcessor-2) Hello james