第24章 KIE Server の機能と拡張

KIE Server の機能は、ビジネスニーズに合わせて有効化、無効化、または拡張可能なプラグインにより決まります。KIE Server は以下の機能および拡張をサポートします。

表24.1 KIE Server の機能と拡張

機能名拡張名説明

KieServer

KieServer

サーバーインスタンスでの KIE コンテナーの作成や削除など、KIE Serverのコア機能を提供します。

BRM

Drools

ファクトの挿入やビジネスルールの実行など、ビジネスルール管理 (BRM) 機能を提供します。

BPM

jBPM

ユーザータスクの管理や、ビジネスプロセスの実行など、Business Process Management (BPM) 機能を提供します。

BPM-UI

jBPM-UI

XML フォームや SVG イメージをプロセスダイアグラムにレンダリングするなど、ビジネスプロセスに関連するユーザーインターフェース機能を提供します。

CaseMgmt

Case-Mgmt

ケースの定義やマイルストーン管理など、ビジネスプロセスのケース管理機能を提供します。

BRP

OptaPlanner

ソルバーの実装など、ビジネスリソースプランニング (BRP) 機能を提供します。

DMN

DMN

DMN データ型の管理や DMN モデルの実行など、Decision Model and Notation (DMN) 機能を提供します。

Swagger

Swagger

KIE Server REST API と対話するための Swagger の Web インターフェース機能を提供します。

実行中の KIE Server インスタンスに対応する拡張を表示するには、以下の REST API エンドポイントに GET 要求を送信して、XML または JSON サーバーの要求を確認します。

KIE Server の情報に対する GET 要求のベース URL

http://SERVER:PORT/kie-server/services/rest/server

KIE Server の情報を含む JSON 応答の例

{
  "type": "SUCCESS",
  "msg": "Kie Server info",
  "result": {
    "kie-server-info": {
      "id": "test-kie-server",
      "version": "7.26.0.20190818-050814",
      "name": "test-kie-server",
      "location": "http://localhost:8080/kie-server/services/rest/server",
      "capabilities": [
        "KieServer",
        "BRM",
        "BPM",
        "CaseMgmt",
        "BPM-UI",
        "BRP",
        "DMN",
        "Swagger"
      ],
      "messages": [
        {
          "severity": "INFO",
          "timestamp": {
            "java.util.Date": 1566169865791
          },
          "content": [
            "Server KieServerInfo{serverId='test-kie-server', version='7.26.0.20190818-050814', name='test-kie-server', location='http:/localhost:8080/kie-server/services/rest/server', capabilities=[KieServer, BRM, BPM, CaseMgmt, BPM-UI, BRP, DMN, Swagger]', messages=null', mode=DEVELOPMENT}started successfully at Sun Aug 18 23:11:05 UTC 2019"
          ]
        }
      ],
      "mode": "DEVELOPMENT"
    }
  }
}

KIE Server 拡張機能を有効または無効にするには、関連する KIE Server システムプロパティー (*.server.ext.disabled) を設定します。たとえば、BRM 機能を無効にするには、org.drools.server.ext.disabled=true システムプロパティーを設定します。全 KIE Server システムプロパティーについては、23章KIE Server のシステムプロパティー を参照してください。

デフォルトでは、KIE Server 拡張機能は REST または JMS データトランスポートで公開され、事前定義済みのクライアント API を使用します。追加の REST エンドポイントで既存の KIE Server 機能を拡張するか、REST または JMS 以外の対応のトランスポートメソッドを拡張するか、KIE Server クライアントの機能を拡張できます。

KIE Server 機能は柔軟であるため、デフォルトの KIE Server 機能にビジネスニーズを合わせるのではなく、KIE Serverインスタンスをビジネスニーズに適合できます。

重要

KIE Server 機能を拡張した場合には、Red Hat では、カスタムの実装や拡張の一部として使用したカスタムコードをサポートしません。

24.1. カスタム REST API エンドポイントを使用した既存の KIE Server 機能の拡張

KIE Server REST API を使用すると、Business Central のユーザーインターフェースなしに、Red Hat Process Automation Manager 内の KIE コンテナーとビジネスアセット (ビジネスルール、プロセスやソルバーなど) と対話できます。利用可能な REST エンドポイントは、KIE Server システムプロパティーで有効にした機能により決まります (例: BRM 機能は org.drools.server.ext.disabled=false)。既存の KIE Server 機能は、カスタムの REST API エンドポイントで拡張し、ビジネスニーズに合わせて KIE Server REST API を適合できます。

たとえば、この手順では、以下のカスタム REST API エンドポイントで Drools KIE Server 機能 (BRM 機能向け) を拡張します。

カスタム REST API エンドポイントの例

/server/containers/instances/{containerId}/ksession/{ksessionId}

このカスタムのエンドポイントの例では、デシジョンエンジンの作業メモリーに挿入するファクト一覧を受け入れ、自動的に全ルールを実行して、指定の KIE コンテナーで KIE セッションからのオブジェクトをすべて取得します。

手順

  1. 空の Maven プロジェクトを作成して、以下のパッケージタイプと依存関係を、プロジェクトの pom.xml ファイルの定義します。

    サンプルプロジェクトの pom.xml ファイルの例

    <packaging>jar</packaging>
    
    <properties>
      <version.org.kie>7.33.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.kie.server</groupId>
        <artifactId>kie-server-rest-common</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>
    </dependencies>

  2. 以下の例のように、プロジェクトの Java クラスに org.kie.server.services.api.KieServerApplicationComponentsService インターフェースを実装します。

    KieServerApplicationComponentsService インターフェースの実装例

    public class CusomtDroolsKieServerApplicationComponentsService implements KieServerApplicationComponentsService {  1
    
        private static final String OWNER_EXTENSION = "Drools";  2
    
        public Collection<Object> getAppComponents(String extension, SupportedTransports type, Object... services) {  3
            // Do not accept calls from extensions other than the owner extension:
            if ( !OWNER_EXTENSION.equals(extension) ) {
                return Collections.emptyList();
            }
    
            RulesExecutionService rulesExecutionService = null;  4
            KieServerRegistry context = null;
    
            for( Object object : services ) {
                if( RulesExecutionService.class.isAssignableFrom(object.getClass()) ) {
                    rulesExecutionService = (RulesExecutionService) object;
                    continue;
                } else if( KieServerRegistry.class.isAssignableFrom(object.getClass()) ) {
                    context = (KieServerRegistry) object;
                    continue;
                }
            }
    
            List<Object> components = new ArrayList<Object>(1);
            if( SupportedTransports.REST.equals(type) ) {
                components.add(new CustomResource(rulesExecutionService, context));  5
            }
    
            return components;
        }
    
    }

    1
    アプリケーションの起動時にデプロイされる KIE Server インフラストラクチャーに REST エンドポイントを提供します。
    2
    この例の Drools 拡張など、拡張する機能を指定します。
    3
    REST コンテナーがデプロイする必要のある全リソースを返します。KIE Server インスタンスで有効化した各拡張で、getAppComponents メソッドを呼び出して、指定した OWNER_EXTENSION 以外の拡張の空のコレクションを、if ( !OWNER_EXTENSION.equals(extension) ) の呼び出しで返します。
    4
    この例の Drools 拡張の RulesExecutionServiceKieServerRegistry サービスなど、指定の拡張から使用するサービスを表示します。
    5
    components リストの一部としてリソースを返す CustomResource クラスと、拡張のトランスポートタイプを REST または JMS に指定します (この例では REST)。
  3. 以下の例のように、KIE Server を使用して新規の REST リソースの機能を追加する CustomResource クラスを実装します。

    CustomResource クラスの実装例

    // Custom base endpoint:
    @Path("server/containers/instances/{containerId}/ksession")
    public class CustomResource {
    
        private static final Logger logger = LoggerFactory.getLogger(CustomResource.class);
    
        private KieCommands commandsFactory = KieServices.Factory.get().getCommands();
    
        private RulesExecutionService rulesExecutionService;
        private KieServerRegistry registry;
    
        public CustomResource() {
    
        }
    
        public CustomResource(RulesExecutionService rulesExecutionService, KieServerRegistry registry) {
            this.rulesExecutionService = rulesExecutionService;
            this.registry = registry;
        }
    
        // Supported HTTP method, path parameters, and data formats:
        @POST
        @Path("/{ksessionId}")
        @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public Response insertFireReturn(@Context HttpHeaders headers,
                @PathParam("containerId") String id,
                @PathParam("ksessionId") String ksessionId,
                String cmdPayload) {
    
            Variant v = getVariant(headers);
            String contentType = getContentType(headers);
    
            // Marshalling behavior and supported actions:
            MarshallingFormat format = MarshallingFormat.fromType(contentType);
            if (format == null) {
                format = MarshallingFormat.valueOf(contentType);
            }
            try {
                KieContainerInstance kci = registry.getContainer(id);
    
                Marshaller marshaller = kci.getMarshaller(format);
    
                List<?> listOfFacts = marshaller.unmarshall(cmdPayload, List.class);
    
                List<Command<?>> commands = new ArrayList<Command<?>>();
                BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands, ksessionId);
    
                for (Object fact : listOfFacts) {
                    commands.add(commandsFactory.newInsert(fact, fact.toString()));
                }
                commands.add(commandsFactory.newFireAllRules());
                commands.add(commandsFactory.newGetObjects());
    
                ExecutionResults results = rulesExecutionService.call(kci, executionCommand);
    
                String result = marshaller.marshall(results);
    
    
                logger.debug("Returning OK response with content '{}'", result);
                return createResponse(result, v, Response.Status.OK);
            } catch (Exception e) {
                // If marshalling fails, return the `call-container` response to maintain backward compatibility:
                String response = "Execution failed with error : " + e.getMessage();
                logger.debug("Returning Failure response with content '{}'", response);
                return createResponse(response, v, Response.Status.INTERNAL_SERVER_ERROR);
            }
    
        }
    }

    この例では、カスタムエンドポイントの CustomResource クラスで、以下のデータと動作を指定します。

    • server/containers/instances/{containerId}/ksession のベースポイントを使用します。
    • POST HTTP メソッドを使用します。
    • REST 要求で以下のデータを指定する必要があります。

      • パスの引数として containerId
      • パスの引数として ksessionId
      • メッセージペイロードとしてファクトの一覧
    • 全 KIE Server データ形式をサポートします。

      • XML (JAXB、XStream)
      • JSON
    • List<?> コレクションにペイロードをアンマーシャリングして、リスト内のアイテムごとに、InsertCommand インスタンスを作成し、その後に FireAllRulesGetObject コマンドを追加します。
    • デシジョンエンジンを呼び出す BatchExecutionCommand インスタンスに全コマンドを追加します。
  4. 新規エンドポイントを KIE Server で検出できるようにするには、Maven プロジェクト内に META-INF/services/org.kie.server.services.api.KieServerApplicationComponentsService ファイルを作成して、このファイルに KieServerApplicationComponentsService 実装クラスの完全修飾名を追加します。たとえば、このファイルには、 org.kie.server.ext.drools.rest.CusomtDroolsKieServerApplicationComponentsService の 1 行が含まれます。
  5. プロジェクトを構築して、作成された JAR ファイルをプロジェクトの ~/kie-server.war/WEB-INF/lib ディレクトリーにコピーします。たとえば、Red Hat JBoss EAP ではこのディレクトリーへのパスは EAP_HOME/standalone/deployments/kie-server.war/WEB-INF/lib です。
  6. KIE Server を起動して、実行中の KIE Server に構築したプロジェクトをデプロイします。プロジェクトは、Business Central インターフェースまたは KIE Server REST API (http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId} への PUT 要求) を使用してデプロイできます。

    実行中の KIE Server にプロジェクトを追加した後に、新しい REST エンドポイントとの対話を開始します。

    今回の例では、以下の情報を使用して新規エンドポイントを呼び出すことができます。

    • 要求 URL 例: http://localhost:8080/kie-server/services/rest/server/containers/instances/demo/ksession/defaultKieSession
    • HTTP メソッド: POST
    • HTTP ヘッダー:

      • Content-Type: application/json
      • Accept: application/json
    • メッセージペイロードの例:

      [
        {
          "org.jbpm.test.Person": {
            "name": "john",
            "age": 25
          }
        },
        {
          "org.jbpm.test.Person": {
            "name": "mary",
            "age": 22
          }
        }
      ]
    • サーバーの応答例: 200 (success)
    • サーバーのログ出力例:

      13:37:20,347 INFO  [stdout] (default task-24) Hello mary
      13:37:20,348 INFO  [stdout] (default task-24) Hello john

24.2. カスタムデータトランスポートを使用するための KIE Server の拡張

デフォルトでは、KIE Server の拡張が REST または JMS データトランスポートを使用して公開されます。KIE Server を拡張して、カスタムのデータトランスポートのサポートを追加し、KIE Server トランスポートプロトコルをビジネスニーズに適合します。

たとえば、以下の手順では、Drools 拡張を使用し、Apache MINA (オープンソースの Java ネットワークアプリケーションフレームワーク) をベースとする KIE Server にカスタムのデータトランスポートを追加します。カスタムの MINA トランスポートの例では、既存のマーシャリング操作に依存し、JSON 形式のみをサポートする文字列ベースのデータを変換します。

手順

  1. 空の Maven プロジェクトを作成して、以下のパッケージタイプと依存関係を、プロジェクトの pom.xml ファイルの定義します。

    サンプルプロジェクトの pom.xml ファイルの例

    <packaging>jar</packaging>
    
    <properties>
      <version.org.kie>7.33.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>

  2. 以下の例のように、プロジェクトの 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, quitting...");
                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 トランスポートの機能を追加する時に KIE 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
    }

    1
    この拡張で対応している機能を指定します。この機能は、KIE Server 内で一意でなければなりません。
    2
    拡張は、人間が解読可能な名前に定義します。
    3
    指定した拡張の起動のタイミングを決定します。他の拡張と依存関係がある拡張の場合には、この設定は親の設定と競合しないようにしてください。たとえば、今回の場合は、このカスタムの拡張は Drools 拡張に依存しており、Drool 拡張の StartOrder0 に設定されているので、このカスタムのアドオン拡張は 0 を超える値でなければなりません (サンプルの実装では 20 に設定)。

    このインターフェースの先程の MinaDroolsKieServerExtension 実装例では、init メソッドが主に、Drools 拡張からサービスを収集して、MINA サーバーをブートストラップ化する要素となっています。KieServerExtension インターフェースの他のメソッドは、標準の実装のままで、インターフェースの要件を満たします。

    TextBasedIoHandlerAdapter クラスは、受信要求に対応する MINA サーバーにあるハンドラーです。

  3. 以下の例のように、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 をサポートし、KIE Server セッションを切断せずにコマンドを送信できます。ストリームモードで KIE Server セッションを終了するには、サーバーに exit または quit コマンドを送信してください。
  4. 新規のデータトランスポートを KIE Server で検出できるようにするには、Maven プロジェクトで META-INF/services/org.kie.server.services.api.KieServerExtension ファイルを作成し、このファイルに KieServerExtension 実装クラスの完全修飾名を追加します。たとえば、このファイルには org.kie.server.ext.mina.MinaDroolsKieServerExtension の 1 行が含まれます。
  5. プロジェクトを構築して、作成された 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 です。
  6. KIE Server を起動して、実行中の KIE Server に構築したプロジェクトをデプロイします。プロジェクトは、Business Central インターフェースまたは KIE Server REST API (http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId} への PUT 要求) を使用してデプロイできます。

    プロジェクトを実行中の KIE Server にデプロイした後に、KIE 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 を使用して KIE Server の 新しい MINA ベースのデータトランスポートと対話できます。

    コマンドターミナルでの Telnet の開始およびポート 9123 での KIE Server の接続

    telnet 127.0.0.1 9123

    コマンドターミナルでの KIE 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

24.3. カスタムクライアント API を使用した KIE Server のクライアント拡張

KIE Server は、KIE Server サービスの使用時に対話可能な、事前定義済みのクライアント API を使用します。カスタムのクライアント API で KIE Server クライアントを拡張して、ビジネスのニーズに KIE Server サービスを適合させます。

たとえば、以下の手順では、カスタムのクライアント API を KIE Server に追加して、Apache MINA (オープンソースの Java ネットワークアプリケーションフレームワーク) をもとにした、カスタムのデータトランスポートに対応します (このシナリオ向けにすでに設定済み)。

手順

  1. 空の Maven プロジェクトを作成して、以下のパッケージタイプと依存関係を、プロジェクトの pom.xml ファイルの定義します。

    サンプルプロジェクトの pom.xml ファイルの例

    <packaging>jar</packaging>
    
    <properties>
       <version.org.kie>7.33.0.Final-redhat-00002</version.org.kie>
     </properties>
    
     <dependencies>
       <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-client</artifactId>
          <version>${version.org.kie}</version>
        </dependency>
       <dependency>
         <groupId>org.drools</groupId>
         <artifactId>drools-compiler</artifactId>
         <version>${version.org.kie}</version>
       </dependency>
     </dependencies>

  2. 以下の例のように、プロジェクトの Java クラスに、適切な ServicesClient インターフェースを実装します。

    RulesMinaServicesClient インターフェースの例

    public interface RulesMinaServicesClient extends RuleServicesClient {
    
    }

    インターフェースをもとにクライアントの実装を登録する必要があるので、特定のインターフェースが必要です。また、指定のインターフェースには実装は 1 つしか指定できません。

    この例では、カスタムの MINA ベースのデータトランスポートが Drools 拡張を使用し、この RulesMinaServicesClient インターフェースの例は、Drools 拡張から、既存の RuleServicesClient クライアント API を拡張します。

  3. 以下の例のように、新規の MINA トランスポートのクライアント機能を追加するのに KIE Server が使用可能な RulesMinaServicesClient インターフェースを実装します。

    RulesMinaServicesClient インターフェースの実装例

    public class RulesMinaServicesClientImpl implements RulesMinaServicesClient {
    
        private String host;
        private Integer port;
    
        private Marshaller marshaller;
    
        public RulesMinaServicesClientImpl(KieServicesConfiguration configuration, ClassLoader classloader) {
            String[] serverDetails = configuration.getServerUrl().split(":");
    
            this.host = serverDetails[0];
            this.port = Integer.parseInt(serverDetails[1]);
    
            this.marshaller = MarshallerFactory.getMarshaller(configuration.getExtraJaxbClasses(), MarshallingFormat.JSON, classloader);
        }
    
        public ServiceResponse<String> executeCommands(String id, String payload) {
    
            try {
                String response = sendReceive(id, payload);
                if (response.startsWith("{")) {
                    return new ServiceResponse<String>(ResponseType.SUCCESS, null, response);
                } else {
                    return new ServiceResponse<String>(ResponseType.FAILURE, response);
                }
            } catch (Exception e) {
                throw new KieServicesException("Unable to send request to KIE Server", e);
            }
        }
    
        public ServiceResponse<String> executeCommands(String id, Command<?> cmd) {
            try {
                String response = sendReceive(id, marshaller.marshall(cmd));
                if (response.startsWith("{")) {
                    return new ServiceResponse<String>(ResponseType.SUCCESS, null, response);
                } else {
                    return new ServiceResponse<String>(ResponseType.FAILURE, response);
                }
            } catch (Exception e) {
                throw new KieServicesException("Unable to send request to KIE Server", e);
            }
        }
    
        protected String sendReceive(String containerId, String content) throws Exception {
    
            // Flatten the content to be single line:
            content = content.replaceAll("\\n", "");
    
            Socket minaSocket = null;
            PrintWriter out = null;
            BufferedReader in = null;
    
            StringBuffer data = new StringBuffer();
            try {
                minaSocket = new Socket(host, port);
                out = new PrintWriter(minaSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(minaSocket.getInputStream()));
    
                // Prepare and send data:
                out.println(containerId + "|" + content);
                // Wait for the first line:
                data.append(in.readLine());
                // Continue as long as data is available:
                while (in.ready()) {
                    data.append(in.readLine());
                }
    
                return data.toString();
            } finally {
                out.close();
                in.close();
                minaSocket.close();
            }
        }
    }

    この実装例は、以下のデータおよび動作を指定します。

    • ソケットベースの通信を使用して簡素化します。
    • KIE Server クライアントのデフォルト設定に依存し、ServerUrl を使用して MINA サーバーのホストとポートを提供します。
    • マーシャリング形式で JSON を指定します。
    • 受信メッセージは左波括弧 { で始まる JSON オブジェクトでなければなりません。
    • 応答の最初の行を待機中に、ブロッキング API と直接、ソケット通信を使用してから、利用可能な行すべてを読み取ります。
    • ストリームモード を使用しないので、コマンドの呼び出し後に KIE Server セッションを切断します。
  4. 以下の例のように、プロジェクトの Java クラスに org.kie.server.client.helper.KieServicesClientBuilder インターフェースを実装します。

    KieServicesClientBuilder インターフェースの実装例

    public class MinaClientBuilderImpl implements KieServicesClientBuilder {  1
    
        public String getImplementedCapability() {  2
            return "BRM-Mina";
        }
    
        public Map<Class<?>, Object> build(KieServicesConfiguration configuration, ClassLoader classLoader) {  3
            Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
    
            services.put(RulesMinaServicesClient.class, new RulesMinaServicesClientImpl(configuration, classLoader));
    
            return services;
        }
    
    }

    1
    一般の KIE Server クライアントインフラストラクチャーにクライアント API を追加できます。
    2
    クライアントが使用する KIE Server 機能 (拡張) を定義します。
    3
    クライアントの実装のマッピングを提供します。キーはインターフェース、値は完全な初期実装です。
  5. 新規のクライアント API を KIE Server クライアントで検出できるようにするには、Maven プロジェクトで META-INF/services/org.kie.server.client.helper.KieServicesClientBuilder ファイルを作成し、このファイルに KieServicesClientBuilder 実装クラスの完全修飾名を追加します。たとえば、このファイルには org.kie.server.ext.mina.client.MinaClientBuilderImpl の 1 行が含まれます。
  6. プロジェクトを構築して、作成された JAR ファイルをプロジェクトの ~/kie-server.war/WEB-INF/lib ディレクトリーにコピーします。たとえば、Red Hat JBoss EAP ではこのディレクトリーへのパスは EAP_HOME/standalone/deployments/kie-server.war/WEB-INF/lib です。
  7. KIE Server を起動して、実行中の KIE Server に構築したプロジェクトをデプロイします。プロジェクトは、Business Central インターフェースまたは KIE Server REST API (http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId} への PUT 要求) を使用してデプロイできます。

    実行中の KIE Server にプロジェクトをデプロイしたあとに、新規の KIE Server クライアントと対話を開始できます。標準の KIE Server クライアントと同じ方法で、クライアント設定とクライアントインスタンスを作成して、タイプ別にサービスクライアントを取得し、クライアントメソッドを呼び出して、新しいクライアントを使用します。

    たとえば、RulesMinaServiceClient クライアントインスタンスを作成して、MINA トランスポートを使用して KIE Server で操作を呼び出すことができます。

    RulesMinaServiceClient クライアントの実装例

    protected RulesMinaServicesClient buildClient() {
        KieServicesConfiguration configuration = KieServicesFactory.newRestConfiguration("localhost:9123", null, null);
        List<String> capabilities = new ArrayList<String>();
        // Explicitly add capabilities (the MINA client does not respond to `get-server-info` requests):
        capabilities.add("BRM-Mina");
    
        configuration.setCapabilities(capabilities);
        configuration.setMarshallingFormat(MarshallingFormat.JSON);
    
        configuration.addJaxbClasses(extraClasses);
    
        KieServicesClient kieServicesClient =  KieServicesFactory.newKieServicesClient(configuration);
    
        RulesMinaServicesClient rulesClient = kieServicesClient.getServicesClient(RulesMinaServicesClient.class);
    
        return rulesClient;
    }

    MINA トランスポートを使用して KIE Server 上で操作を呼び出す設定例

    RulesMinaServicesClient rulesClient = buildClient();
    
    List<Command<?>> commands = new ArrayList<Command<?>>();
    BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands, "defaultKieSession");
    
    Person person = new Person();
    person.setName("mary");
    commands.add(commandsFactory.newInsert(person, "person"));
    commands.add(commandsFactory.newFireAllRules("fired"));
    
    ServiceResponse<String> response = rulesClient.executeCommands(containerId, executionCommand);
    Assert.assertNotNull(response);
    
    Assert.assertEquals(ResponseType.SUCCESS, response.getType());
    
    String data = response.getResult();
    
    Marshaller marshaller = MarshallerFactory.getMarshaller(extraClasses, MarshallingFormat.JSON, this.getClass().getClassLoader());
    
    ExecutionResultImpl results = marshaller.unmarshall(data, ExecutionResultImpl.class);
    Assert.assertNotNull(results);
    
    Object personResult = results.getValue("person");
    Assert.assertTrue(personResult instanceof Person);
    
    Assert.assertEquals("mary", ((Person) personResult).getName());
    Assert.assertEquals("JBoss Community", ((Person) personResult).getAddress());
    Assert.assertEquals(true, ((Person) personResult).isRegistered());