21.3. 使用自定义客户端 API 扩展 KIE 服务器客户端
KIE 服务器使用预定义的客户端 API,您可以与之交互来使用 KIE 服务器服务。您可以使用自定义客户端 API 扩展 KIE 服务器客户端,以满足您的业务需求。
例如,这个流程将自定义客户端 API 添加到 KIE Server 以容纳自定义数据传输(之前为这种情况配置),它基于 Apache MINA,它是一个开源 Java 网络应用程序框架。
流程
创建一个空的 Maven 项目,并在项目的
pom.xml
文件中定义以下打包类型和依赖项:示例项目中的 pom.xml 文件示例
<packaging>jar</packaging> <properties> <version.org.kie>7.59.0.Final-redhat-00006</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>
在项目中的 Java 类中实施相关的
ServicesClient
接口,如下例所示:RulesMinaServicesClient
接口示例public interface RulesMinaServicesClient extends RuleServicesClient { }
需要一个特定的接口,因为您必须根据接口注册客户端实现,且对于给定接口只能有一个实施。
在本例中,自定义基于 MINA 的数据传输使用
Drools
扩展,因此本例RulesMinaServicesClient
接口会扩展Drools
扩展的现有RuleServicesClient
客户端 API。实施 KIE 服务器可以用来为新的 MINA 传输提供额外的客户端功能的
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 指定为 marshalling 格式
-
需要收到的消息是以打开的 bracket
{
开头的 JSON 对象。 - 在等待响应的第一行时,使用与阻塞 API 的直接套接字通信,然后读取所有可用的行
- 不使用流模式,因此在调用命令后断开 KIE 服务器会话
在项目中的 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; } }
-
要使新的客户端 API 发现 KIE 服务器客户端,请在 Maven 项目中创建一个
META-INF/services/org.kie.server.client.helper.KieServicesClientBuilder
文件,并在文件中添加KieServicesClientBuilder
实施类的完全限定名称。在本例中,文件包含一行org.kie.server.ext.mina.client.MinaClientBuilderImpl
。 -
构建项目并将生成的 JAR 文件复制到项目的
~/kie-server.war/WEB-INF/lib
目录中。例如,在红帽 JBoss EAP 上,此目录的路径为EAP_HOME/standalone/deployments/kie-server.war/WEB-INF/lib
。 启动 KIE 服务器,并将构建的项目部署到正在运行的 KIE 服务器。您可以使用 Business Central 接口或 KIE 服务器 REST API 部署项目(
PUT
请求http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId}
)。在运行的 KIE Server 上部署项目后,您可以开始与新的 KIE Server 客户端交互。您可以通过创建客户端配置和客户端实例、按类型检索服务客户端并调用客户端方法,按照标准 KIE 服务器客户端使用新客户端。
在本例中,您可以创建一个
RulesMinaServiceClient
客户端实例,并通过 MINA 传输在 KIE 服务器上调用操作:创建
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 传输调用操作的示例配置
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());