21.3. 使用自定义客户端 API 扩展 KIE 服务器客户端
KIE 服务器使用预定义的客户端 API,您可以与之交互以使用 KIE 服务器服务。您可以使用自定义客户端 API 扩展 KIE 服务器客户端,以满足您的业务需求。
例如,这个步骤将自定义客户端 API 添加到 KIE 服务器,以适应自定义数据传输(之前为本情景)基于 Apache MINA(开源 Java 网络应用程序框架)。
流程
创建一个空的 Maven 项目,并在项目的
pom.xml
文件中定义以下打包类型和依赖项:示例项目中的 pom.xml 文件示例
<packaging>jar</packaging> <properties> <version.org.kie>7.67.0.Final-redhat-00024</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 服务器客户端的默认配置,并使用
ServerUrl
提供 MINA 服务器的主机和端口 - 将 JSON 指定为 marshalling 格式
-
需要接收消息作为以 open bracket
{
开头的 JSON 对象 - 在等待响应的第一行时,使用直接套接字与阻塞 API 通信,然后读取所有可用的行
- 不要使用 流模式, 因此在调用命令后断开 KIE 服务器会话
在项目中的 Java 类中实施
org.kie.client.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 服务器客户端,请在 文件中创建一个
META-INF/services/org.kie.client.client.helper
.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 服务器上部署项目后,您可以开始与新的 KIE 服务器客户端交互。您可以采用与标准 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 传输调用 KIE 服务器操作的示例配置
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());