[ https://issues.apache.org/jira/browse/CAMEL-12964?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16707041#comment-16707041 ]
ASF GitHub Bot commented on CAMEL-12964: ---------------------------------------- oscerd closed pull request #2644: CAMEL-12964: Initial import of jBPM CamelWIH and Command. URL: https://github.com/apache/camel/pull/2644 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/components/camel-jbpm/pom.xml b/components/camel-jbpm/pom.xml index 2a5a161e5db..02b4540db60 100644 --- a/components/camel-jbpm/pom.xml +++ b/components/camel-jbpm/pom.xml @@ -92,6 +92,15 @@ <optional>true</optional> </dependency> + <!-- jBPM WorkItems --> + <dependency> + <groupId>org.jbpm</groupId> + <artifactId>jbpm-workitems-core</artifactId> + <version>${jbpm-version}</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> + <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> @@ -128,6 +137,24 @@ <artifactId>camel-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jbpm</groupId> + <artifactId>jbpm-workitems-core</artifactId> + <version>${jbpm-version}</version> + <type>test-jar</type> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>xml-apis</groupId> + <artifactId>xml-apis</artifactId> + </exclusion> + </exclusions> + </dependency> </dependencies> </project> diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java index 8341cfd619c..94ff0ca77ba 100644 --- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConstants.java @@ -43,4 +43,12 @@ String JBPM_TASK_EVENT_LISTENER = "task"; String JBPM_CASE_EVENT_LISTENER = "case"; String JBPM_EVENT_EMITTER = "emitter"; + + String GLOBAL_CAMEL_CONTEXT_SERVICE_KEY = "GlobalCamelService"; + String DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX = "_CamelService"; + String CAMEL_ENDPOINT_ID_WI_PARAM = "CamelEndpointId"; + String RESPONSE_WI_PARAM = "Response"; + String MESSAGE_WI_PARAM = "Message"; + + } diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java index 0e297bece0f..659a498c2db 100644 --- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/server/CamelKieServerExtension.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; +import org.apache.camel.component.jbpm.JBPMConstants; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.model.FromDefinition; import org.apache.camel.model.RouteDefinition; @@ -85,7 +86,7 @@ public void init(KieServerImpl kieServer, KieServerRegistry registry) { } } - ServiceRegistry.get().register("GlobalCamelService", this.camel); + ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, this.camel); } @Override @@ -117,7 +118,7 @@ public void createContainer(String id, KieContainerInstance kieContainerInstance context.start(); camelContexts.put(id, context); - ServiceRegistry.get().register(id + "_CamelService", context); + ServiceRegistry.get().register(id + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX, context); } } catch (Exception e) { diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelCommand.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelCommand.java new file mode 100644 index 00000000000..a26aa321710 --- /dev/null +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelCommand.java @@ -0,0 +1,85 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.ExchangeBuilder; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.jbpm.services.api.service.ServiceRegistry; +import org.kie.api.executor.Command; +import org.kie.api.executor.CommandContext; +import org.kie.api.executor.ExecutionResults; +import org.kie.api.runtime.manager.RuntimeManager; +import org.kie.api.runtime.process.WorkItem; +import org.kie.internal.runtime.Cacheable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Camel jBPM {@link Command} which allows to call Camel routes with a <code>direct</code> endpoint. + * <p/> + * The command passes the {@WorkItem} retrieved from the {@link CommandContext} to the route that has a consumer on the endpoint-id + * that can be passed with the <code>camel-endpoint-id</code> {@link WorkItem} parameter. E.g. when a the value "myCamelEndpoint" is passed to the + * {link WorkItem} via the <code>camel-endpoint-id</code> parameter, this {@link Command} will send the {@link WorkItem} to + * the Camel URI <code>direct://myCamelEndpoint</code>. + * <p/> + * The body of the result {@link Message} of the invocation is returned via the <code>Response</code> parameter. Access to the raw response + * {@link Message} is provided via the <code>Message</code> parameter. This gives the user access to more advanced fields like message headers + * and attachments. + */ +public abstract class AbstractCamelCommand implements Command, + Cacheable { + + private static final Logger logger = LoggerFactory.getLogger(AbstractCamelCommand.class); + + public AbstractCamelCommand() { + } + + @Override + public ExecutionResults execute(CommandContext ctx) throws Exception { + + WorkItem workItem = (WorkItem) ctx.getData("workItem"); + + String camelEndpointId = (String) workItem.getParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM); + + // We only support direct. We don't need to support more, as direct simply gives us the entrypoint into the actual Camel Routes. + String camelUri = "direct://" + camelEndpointId; + + ProducerTemplate producerTemplate = getProducerTemplate(ctx); + Exchange inExchange = ExchangeBuilder.anExchange(producerTemplate.getCamelContext()).withBody(workItem).build(); + Exchange outExchange = producerTemplate.send(camelUri, inExchange); + // producerTemplate.send does not throw exceptions, instead they are set on the returned Exchange. + if (outExchange.getException() != null) { + throw outExchange.getException(); + } + Message outMessage = outExchange.getOut(); + + ExecutionResults results = new ExecutionResults(); + Object response = outMessage.getBody(); + results.setData(JBPMConstants.RESPONSE_WI_PARAM, response); + results.setData(JBPMConstants.MESSAGE_WI_PARAM, outMessage); + + return results; + } + + protected abstract ProducerTemplate getProducerTemplate(CommandContext ctx); + +} \ No newline at end of file diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelWorkItemHandler.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelWorkItemHandler.java new file mode 100644 index 00000000000..23d7a35051e --- /dev/null +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/AbstractCamelWorkItemHandler.java @@ -0,0 +1,153 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.jbpm.process.workitem.core.AbstractLogOrThrowWorkItemHandler; +import org.jbpm.services.api.service.ServiceRegistry; +import org.kie.api.runtime.manager.RuntimeManager; +import org.kie.api.runtime.process.WorkItem; +import org.kie.api.runtime.process.WorkItemHandler; +import org.kie.api.runtime.process.WorkItemManager; +import org.kie.internal.runtime.Cacheable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Camel jBPM {@link WorkItemHandler} which allows to call Camel routes with a <code>direct</code> endpoint. + * <p/> + * The handler passes the {@WorkItem} to the route that has a consumer on the endpoint-id that can be passed with the + * <code>CamelEndpointId</code>{@link WorkItem} parameter. E.g. when a the value "myCamelEndpoint" is passed to the {link WorkItem} via + * the <code>CamelEndpointId</code> parameter, this command will send the {@link WorkItem} to the Camel URI + * <code>direct://myCamelEndpoint</code>. + * <p/> + * The body of the result {@link Message} of the invocation is returned via the <code>Response</code> parameter. Access to the raw response + * {@link Message} is provided via the <code>Message</code> parameter. This gives the user access to more advanced fields like message + * headers and attachments. + * <p/> + * This handler can be constructed in multiple ways. When you don't pass a {@link RuntimeManager} to the constructor, the handler will try + * to find the global KIE {@link CamelContext} from the <code>jBPM</code> {@link ServiceRegistry}. When the {@link RuntimeManager} is passed + * to the constructor, the handler will retrieve and use the {@link CamelContext} bound to the {@link RuntimeManage} from the + * {@link ServiceRegistry}. When a <code>CamelEndpointId</code> is passed to the constructor, the handler will send all requests to the + * Camel route that is consuming from that endpoint, unless the endpoint is overridden by passing a the <code>CamelEndpointId</code> in + * the {@link WorkItem} parameters. + * + */ +public abstract class AbstractCamelWorkItemHandler extends AbstractLogOrThrowWorkItemHandler implements Cacheable { + + private static Logger logger = LoggerFactory.getLogger(AbstractCamelWorkItemHandler.class); + + private final ProducerTemplate producerTemplate; + + private final String camelEndpointId; + + /** + * Default Constructor. This creates a {@link ProducerTemplate} for the global {@link CamelContext}. + */ + public AbstractCamelWorkItemHandler() { + this(""); + } + + public AbstractCamelWorkItemHandler(String camelEndointId) { + CamelContext globalCamelContext = (CamelContext) ServiceRegistry.get().service(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY); + this.producerTemplate = globalCamelContext.createProducerTemplate(); + this.camelEndpointId = camelEndointId; + } + + /** + * Constructor which accepts {@link RuntimeManager}. This causes this WorkItemHanlder to create a {@link ProducerTemplate} for the + * runtime specific {@link CamelContext}. + */ + public AbstractCamelWorkItemHandler(RuntimeManager runtimeManager) { + this(runtimeManager, ""); + } + + public AbstractCamelWorkItemHandler(RuntimeManager runtimeManager, String camelEndpointId) { + String runtimeCamelContextKey = runtimeManager.getIdentifier() + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX; + CamelContext runtimeCamelContext = (CamelContext) ServiceRegistry.get().service(runtimeCamelContextKey); + this.producerTemplate = runtimeCamelContext.createProducerTemplate(); + this.camelEndpointId = camelEndpointId; + } + + public void executeWorkItem(WorkItem workItem, final WorkItemManager manager) { + + String workItemCamelEndpointId = getCamelEndpointId(workItem); + + // We only support direct. We don't need to support more, as direct simply gives us the entrypoint into the actual Camel Routes. + String camelUri = "direct://" + workItemCamelEndpointId; + + try { + Exchange requestExchange = buildExchange(producerTemplate, workItem); + logger.debug("Sending Camel Exchange to: " + camelUri); + Exchange responseExchange = producerTemplate.send(camelUri, requestExchange); + // producerTemplate.send does not throw exceptions, instead they are set on the returned Exchange. + if (responseExchange.getException() != null) { + throw responseExchange.getException(); + } + handleResponse(responseExchange, workItem, manager); + } catch (Exception e) { + handleException(e); + } + } + + protected String getCamelEndpointId(WorkItem workItem) { + String workItemCamelEndpointId = (String) workItem.getParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM); + + if (camelEndpointId != null && !camelEndpointId.isEmpty()) { + if (workItemCamelEndpointId != null && !workItemCamelEndpointId.isEmpty()) { + logger.debug( + "The Camel Endpoint ID has been set on both the WorkItemHanlder and WorkItem. The '" + + JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM + + "' configured on the WorkItem overrides the global configuation."); + } else { + workItemCamelEndpointId = camelEndpointId; + } + } + + if (workItemCamelEndpointId == null || workItemCamelEndpointId.isEmpty()) { + throw new IllegalArgumentException( + "No Camel Endpoint ID specified. Please configure the '" + JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM + + "' in either the constructor of this WorkItemHandler, or pass it via the " + + JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM + "' WorkItem parameter."); + } + return workItemCamelEndpointId; + } + + protected abstract void handleResponse(Exchange responseExchange, WorkItem workItem, WorkItemManager manager); + + protected abstract Exchange buildExchange(ProducerTemplate template, WorkItem workItem); + + public void abortWorkItem(WorkItem workItem, WorkItemManager manager) { + // Do nothing, cannot be aborted + } + + @Override + public void close() { + try { + this.producerTemplate.stop(); + } catch (Exception e) { + logger.warn("Error encountered while closing the Camel Producer Template.", e); + // Not much we can do here, so swallowing exception. + } + } + +} \ No newline at end of file diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommand.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommand.java new file mode 100644 index 00000000000..009b9094686 --- /dev/null +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommand.java @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.jbpm.services.api.service.ServiceRegistry; +import org.kie.api.executor.CommandContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * CamelCommand that uses the {@link CamelContext} registered on the {@link ServiceRegistry} for this specific deployment. + */ +public class DeploymentContextCamelCommand extends AbstractCamelCommand { + + private final Map<String, ProducerTemplate> templates = new ConcurrentHashMap<>(); + + private static final Logger logger = LoggerFactory.getLogger(DeploymentContextCamelCommand.class); + + @Override + protected ProducerTemplate getProducerTemplate(CommandContext ctx) { + String deploymentId = (String) ctx.getData("deploymentId"); + ProducerTemplate template = templates.get(deploymentId); + + if (template == null) { + synchronized (this) { + template = templates.get(deploymentId); + if (template == null) { + CamelContext deploymentCamelContext = (CamelContext) ServiceRegistry.get() + .service(deploymentId + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX); + template = deploymentCamelContext.createProducerTemplate(); + templates.put(deploymentId, template); + } + } + } + return template; + } + + @Override + public void close() { + for (ProducerTemplate nextTemplate : templates.values()) { + try { + nextTemplate.stop(); + } catch (Exception e) { + logger.warn("Error encountered while closing the Camel Producer Template.", e); + // Not much we can do here, so swallowing exception. + } + } + + } + +} diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommand.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommand.java new file mode 100644 index 00000000000..e129a120a1b --- /dev/null +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommand.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.jbpm.services.api.service.ServiceRegistry; +import org.kie.api.executor.CommandContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * CamelCommand that uses the global {@link CamelContext} registered on the {@link ServiceRegistry}. + */ +public class GlobalContextCamelCommand extends AbstractCamelCommand { + + private final ProducerTemplate globalContextProducerTemplate; + + private static final Logger logger = LoggerFactory.getLogger(GlobalContextCamelCommand.class); + + public GlobalContextCamelCommand() { + CamelContext globalCamelContext = (CamelContext) ServiceRegistry.get().service(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY); + this.globalContextProducerTemplate = globalCamelContext.createProducerTemplate(); + } + + @Override + protected ProducerTemplate getProducerTemplate(CommandContext ctx) { + return globalContextProducerTemplate; + } + + @Override + public void close() { + try { + this.globalContextProducerTemplate.stop(); + } catch (Exception e) { + logger.warn("Error encountered while closing the Camel Producer Template.", e); + // Not much we can do here, so swallowing exception. + } + } + + +} diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/InOnlyCamelWorkItemHandler.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/InOnlyCamelWorkItemHandler.java new file mode 100644 index 00000000000..b97b0ad4156 --- /dev/null +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/InOnlyCamelWorkItemHandler.java @@ -0,0 +1,107 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.ExchangeBuilder; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.process.workitem.core.util.Wid; +import org.jbpm.process.workitem.core.util.WidMavenDepends; +import org.jbpm.process.workitem.core.util.WidParameter; +import org.jbpm.process.workitem.core.util.WidResult; +import org.jbpm.process.workitem.core.util.service.WidAction; +import org.jbpm.process.workitem.core.util.service.WidService; +import org.kie.api.runtime.manager.RuntimeManager; +import org.kie.api.runtime.process.WorkItem; +import org.kie.api.runtime.process.WorkItemHandler; +import org.kie.api.runtime.process.WorkItemManager; + +/** + * Camel jBPM {@link WorkItemHandler} that sends {@link Exchange Exchanges} with an <code>InOnly</code> Message Exchange Pattern. + * <p/> + * This handler does <b>NOT<b/> complete the {@link WorkItem}, and will not parse any response from the Camel route, other than possible exceptions. + * The use-case for this handler is asynchronous, one-way, communication, where an external party is responsible for completing the + * {@link WorkItem} at a later point in time. + * <p/> + * The handler creates a Camel Exchange and sets the {@link WorkItem} as the body of the {@link Message}. Furthermore, the following message + * headers are set: + * <ul> + * <li>deploymentId</li> + * <li>processInstanceId</li> + * <li>workItemId</li> + * </ul> + */ +@Wid( + widfile = "InOnlyCamelConnector.wid", + name = "InOnlyCamelConnector", + displayName = "InOnlyCamelConnector", + defaultHandler = "mvel: new org.apache.camel.component.jbpm.workitem.InOnlyCamelWorkitemHandler()", + documentation = "${artifactId}/index.html", + parameters = { + @WidParameter(name = JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM) + }, + results = { + @WidResult(name = JBPMConstants.RESPONSE_WI_PARAM), + @WidResult(name = JBPMConstants.MESSAGE_WI_PARAM) }, + mavenDepends = { + @WidMavenDepends(group = "${groupId}", + artifact = "${artifactId}", + version = "${version}") + }, + serviceInfo = @WidService(category = "${name}", + description = "${description}", + keywords = "apache,camel,payload,route,connector", + action = @WidAction(title = "Send payload to a Camel endpoint"))) +public class InOnlyCamelWorkItemHandler extends AbstractCamelWorkItemHandler { + + public InOnlyCamelWorkItemHandler() { + super(); + } + + public InOnlyCamelWorkItemHandler(String camelEndpointId) { + super(camelEndpointId); + } + + public InOnlyCamelWorkItemHandler(RuntimeManager runtimeManager) { + super(runtimeManager); + } + + public InOnlyCamelWorkItemHandler(RuntimeManager runtimeManager, String camelEndpointId) { + super(runtimeManager, camelEndpointId); + } + + @Override + protected void handleResponse(Exchange responseExchange, WorkItem workItem, WorkItemManager manager) { + // no-op. There is no response for InOnly, so need to handle anything + } + + @Override + protected Exchange buildExchange(ProducerTemplate template, WorkItem workItem) { + return ExchangeBuilder.anExchange(template.getCamelContext()) + .withPattern(ExchangePattern.InOnly) + .withHeader("deploymentId", ((WorkItemImpl) workItem).getDeploymentId()) + .withHeader("processInstanceId", workItem.getProcessInstanceId()) + .withHeader("workItemId", workItem.getId()) + .withBody(workItem).build(); + } + +} diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/InOutCamelWorkItemHandler.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/InOutCamelWorkItemHandler.java new file mode 100644 index 00000000000..a8482dde6d9 --- /dev/null +++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/workitem/InOutCamelWorkItemHandler.java @@ -0,0 +1,117 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.Exchange; +import org.apache.camel.ExchangePattern; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.ExchangeBuilder; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.process.workitem.core.util.Wid; +import org.jbpm.process.workitem.core.util.WidMavenDepends; +import org.jbpm.process.workitem.core.util.WidParameter; +import org.jbpm.process.workitem.core.util.WidResult; +import org.jbpm.process.workitem.core.util.service.WidAction; +import org.jbpm.process.workitem.core.util.service.WidService; +import org.kie.api.runtime.manager.RuntimeManager; +import org.kie.api.runtime.process.WorkItem; +import org.kie.api.runtime.process.WorkItemHandler; +import org.kie.api.runtime.process.WorkItemManager; + +/** + * Camel jBPM {@link WorkItemHandler} that sends {@link Exchange Exchanges} with an <code>InOut</code> Message Exchange Pattern. + * <p/> + * This handler parses the response message from the given Camel route and completes the {@link WorkItem}. The use-case for this handler is + * synchronous, request-response style, communication. + * <p/> + * The handler creates a Camel Exchange and sets the {@link WorkItem} as the body of the {@link Message}. Furthermore, the following message + * headers are set: + * <ul> + * <li>deploymentId</li> + * <li>processInstanceId</li> + * <li>workItemId</li> + * </ul> + */ +@Wid( + widfile = "InOutCamelConnector.wid", + name = "InOutCamelConnector", + displayName = "InOutCamelConnector", + defaultHandler = "mvel: new org.apache.camel.component.jbpm.workitem.InOutCamelWorkitemHandler()", + documentation = "${artifactId}/index.html", + parameters = { + @WidParameter(name = JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM) + }, + results = { + @WidResult(name = JBPMConstants.RESPONSE_WI_PARAM), + @WidResult(name = JBPMConstants.MESSAGE_WI_PARAM) }, + mavenDepends = { + @WidMavenDepends(group = "${groupId}", + artifact = "${artifactId}", + version = "${version}") + }, + serviceInfo = @WidService(category = "${name}", + description = "${description}", + keywords = "apache,camel,payload,route,connector", + action = @WidAction(title = "Send payload to a Camel endpoint"))) +public class InOutCamelWorkItemHandler extends AbstractCamelWorkItemHandler { + + public InOutCamelWorkItemHandler() { + super(); + } + + public InOutCamelWorkItemHandler(String camelEndpointId) { + super(camelEndpointId); + } + + public InOutCamelWorkItemHandler(RuntimeManager runtimeManager) { + super(runtimeManager); + } + + public InOutCamelWorkItemHandler(RuntimeManager runtimeManager, String camelEndpointId) { + super(runtimeManager, camelEndpointId); + } + + @Override + protected void handleResponse(Exchange responseExchange, WorkItem workItem, WorkItemManager manager) { + Message outMessage = responseExchange.getOut(); + + Map<String, Object> result = new HashMap<>(); + Object response = outMessage.getBody(); + result.put(JBPMConstants.RESPONSE_WI_PARAM, response); + result.put(JBPMConstants.MESSAGE_WI_PARAM, outMessage); + + manager.completeWorkItem(workItem.getId(), result); + } + + @Override + protected Exchange buildExchange(ProducerTemplate template, WorkItem workItem) { + return ExchangeBuilder.anExchange(template.getCamelContext()) + .withPattern(ExchangePattern.InOut) + .withHeader("deploymentId", ((WorkItemImpl) workItem).getDeploymentId()) + .withHeader("processInstanceId", workItem.getProcessInstanceId()) + .withHeader("workItemId", workItem.getId()) + .withBody(workItem) + .build(); + } + +} diff --git a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/CamelWorkItemHandlerIntegrationTests.java b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/CamelWorkItemHandlerIntegrationTests.java new file mode 100644 index 00000000000..4e594ddacc6 --- /dev/null +++ b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/CamelWorkItemHandlerIntegrationTests.java @@ -0,0 +1,205 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import static org.hamcrest.CoreMatchers.*; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.bpmn2.handler.WorkItemHandlerRuntimeException; +import org.jbpm.process.workitem.core.TestWorkItemManager; +import org.jbpm.services.api.service.ServiceRegistry; +import org.junit.Test; +import org.kie.api.runtime.process.WorkItemHandler; + +//http://camel.apache.org/using-getin-or-getout-methods-on-exchange.html +//http://camel.apache.org/async.html +public class CamelWorkItemHandlerIntegrationTests extends CamelTestSupport { + + @EndpointInject(uri = "mock:result") + protected MockEndpoint resultEndpoint; + + @Produce(uri = "direct:start") + protected ProducerTemplate template; + + @Test + public void testSyncInOnly() throws Exception { + // Setup + String routeId = "testSyncInOnlyExceptionRoute"; + RouteBuilder builder = new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId(routeId) + .setBody(simple("${body.getParameter(\"Request\")}")) + .to("mock:result"); + } + }; + context.addRoutes(builder); + try { + // Register the Camel Context with the jBPM ServiceRegistry. + ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, context); + + // Test + String expectedBody = "helloRequest"; + resultEndpoint.expectedBodiesReceived(expectedBody); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, "start"); + workItem.setParameter("Request", expectedBody); + + TestWorkItemManager manager = new TestWorkItemManager(); + + WorkItemHandler handler = new InOnlyCamelWorkItemHandler(); + + handler.executeWorkItem(workItem, manager); + + // Assertions + assertThat(manager.getResults().size(), equalTo(0)); + resultEndpoint.assertIsSatisfied(); + } finally { + // Cleanup + context.removeRoute(routeId); + } + } + + @Test(expected = WorkItemHandlerRuntimeException.class) + public void testSyncInOnlyException() throws Exception { + // Setup + String routeId = "testSyncInOnlyExceptionRoute"; + RouteBuilder builder = new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId(routeId) + .setBody(simple("${body.getParameter(\"Request\")}")) + .throwException(new IllegalArgumentException("Illegal contennt!")) + .to("mock:result"); + } + }; + context.addRoutes(builder); + try { + // Register the Camel Context with the jBPM ServiceRegistry. + ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, context); + + // Test + String expectedBody = "helloRequest"; + resultEndpoint.expectedBodiesReceived(expectedBody); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, "start"); + workItem.setParameter("Request", expectedBody); + + TestWorkItemManager manager = new TestWorkItemManager(); + + WorkItemHandler handler = new InOnlyCamelWorkItemHandler(); + + handler.executeWorkItem(workItem, manager); + + // Assertions + assertThat(manager.getResults().size(), equalTo(0)); + resultEndpoint.assertIsSatisfied(); + } finally { + // Cleanup + context.removeRoute(routeId); + } + } + + @Test + public void testSyncInOut() throws Exception { + // Setup + String routeId = "testSyncInOnlyExceptionRoute"; + RouteBuilder builder = new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId(routeId) + .setBody(simple("${body.getParameter(\"Request\")}")) + .to("mock:result"); + } + }; + context.addRoutes(builder); + try { + // Register the Camel Context with the jBPM ServiceRegistry. + ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, context); + + // Test + String expectedBody = "helloRequest"; + resultEndpoint.expectedBodiesReceived(expectedBody); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, "start"); + workItem.setParameter("Request", expectedBody); + + TestWorkItemManager manager = new TestWorkItemManager(); + + AbstractCamelWorkItemHandler handler = new InOutCamelWorkItemHandler(); + + handler.executeWorkItem(workItem, manager); + + // Assertions + assertThat(manager.getResults().size(), equalTo(1)); + resultEndpoint.assertIsSatisfied(); + } finally { + // Cleanup + context.removeRoute(routeId); + } + + } + + @Test(expected = WorkItemHandlerRuntimeException.class) + public void testSyncInOutException() throws Exception { + // Setup + String routeId = "testSyncInOutExceptionRoute"; + RouteBuilder builder = new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId(routeId) + .setBody(simple("${body.getParameter(\"Request\")}")) + .throwException(new IllegalArgumentException("Illegal contennt!")) + .to("mock:result"); + } + }; + context.addRoutes(builder); + try { + // Register the Camel Context with the jBPM ServiceRegistry. + ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, context); + + // Test + String expectedBody = "helloRequest"; + resultEndpoint.expectedBodiesReceived(expectedBody); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, "start"); + workItem.setParameter("Request", expectedBody); + + TestWorkItemManager manager = new TestWorkItemManager(); + + WorkItemHandler handler = new InOutCamelWorkItemHandler(); + + handler.executeWorkItem(workItem, manager); + } finally { + // Cleanup + context.removeRoute(routeId); + } + } + +} diff --git a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommandTest.java b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommandTest.java new file mode 100644 index 00000000000..e1aef21c32a --- /dev/null +++ b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/DeploymentContextCamelCommandTest.java @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.services.api.service.ServiceRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.api.executor.Command; +import org.kie.api.executor.CommandContext; +import org.kie.api.executor.ExecutionResults; +import org.kie.api.runtime.manager.RuntimeManager; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class DeploymentContextCamelCommandTest { + + @Mock + ProducerTemplate producerTemplate; + + @Mock + Exchange outExchange; + + @Mock + Message outMessage; + + @Mock + CamelContext camelContext; + + @Mock + RuntimeManager runtimeManager; + + @Mock + CommandContext commandContext; + + @Test + public void testExecuteCommandDeploymentCamelContext() throws Exception { + + String camelEndpointId = "testCamelRoute"; + String camelRouteUri = "direct://" + camelEndpointId; + + String testReponse = "testResponse"; + + String deploymentId = "testDeployment"; + + when(producerTemplate.send(eq(camelRouteUri), any(Exchange.class))).thenReturn(outExchange); + when(producerTemplate.getCamelContext()).thenReturn(camelContext); + + when(camelContext.createProducerTemplate()).thenReturn(producerTemplate); + + when(outExchange.getOut()).thenReturn(outMessage); + when(outMessage.getBody()).thenReturn(testReponse); + + //Register the RuntimeManager bound camelcontext. + ServiceRegistry.get().register(deploymentId + JBPMConstants.DEPLOYMENT_CAMEL_CONTEXT_SERVICE_KEY_POSTFIX, camelContext); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, camelEndpointId); + workItem.setParameter("Request", "someRequest"); + + when(commandContext.getData("workItem")).thenReturn(workItem); + when(commandContext.getData("deploymentId")).thenReturn(deploymentId); + + Command command = new DeploymentContextCamelCommand(); + ExecutionResults results = command.execute(commandContext); + + assertNotNull(results); + assertEquals(2, results.getData().size()); + assertEquals(testReponse, results.getData().get(JBPMConstants.RESPONSE_WI_PARAM)); + } +} diff --git a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommandTest.java b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommandTest.java new file mode 100644 index 00000000000..048ec72840a --- /dev/null +++ b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/GlobalContextCamelCommandTest.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.services.api.service.ServiceRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.api.executor.Command; +import org.kie.api.executor.CommandContext; +import org.kie.api.executor.ExecutionResults; +import org.kie.api.runtime.manager.RuntimeManager; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class GlobalContextCamelCommandTest { + + @Mock + ProducerTemplate producerTemplate; + + @Mock + Exchange outExchange; + + @Mock + Message outMessage; + + @Mock + CamelContext camelContext; + + @Mock + RuntimeManager runtimeManager; + + @Mock + CommandContext commandContext; + + @Test + public void testExecuteGlobalCommand() throws Exception { + + String camelEndpointId = "testCamelRoute"; + String camelRouteUri = "direct://" + camelEndpointId; + + String testReponse = "testResponse"; + + String runtimeManagerId = "testRuntimeManager"; + + when(producerTemplate.send(eq(camelRouteUri), any(Exchange.class))).thenReturn(outExchange); + + + when(producerTemplate.getCamelContext()).thenReturn(camelContext); + + when(camelContext.createProducerTemplate()).thenReturn(producerTemplate); + + when(outExchange.getOut()).thenReturn(outMessage); + when(outMessage.getBody()).thenReturn(testReponse); + + //Register the RuntimeManager bound camelcontext. + ServiceRegistry.get().register(JBPMConstants.GLOBAL_CAMEL_CONTEXT_SERVICE_KEY, camelContext); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, camelEndpointId); + workItem.setParameter("Request", "someRequest"); + + when(commandContext.getData(anyString())).thenReturn(workItem); + + Command command = new GlobalContextCamelCommand(); + ExecutionResults results = command.execute(commandContext); + + + assertNotNull(results); + assertEquals(2, results.getData().size()); + assertEquals(testReponse, results.getData().get(JBPMConstants.RESPONSE_WI_PARAM)); + } +} diff --git a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/InOnlyCamelWorkItemHandlerTest.java b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/InOnlyCamelWorkItemHandlerTest.java new file mode 100644 index 00000000000..a862f223801 --- /dev/null +++ b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/InOnlyCamelWorkItemHandlerTest.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.apache.camel.impl.DefaultHeadersMapFactory; +import org.apache.camel.spi.HeadersMapFactory; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.process.workitem.core.TestWorkItemManager; +import org.jbpm.services.api.service.ServiceRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.api.runtime.manager.RuntimeManager; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class InOnlyCamelWorkItemHandlerTest { + + @Mock + ProducerTemplate producerTemplate; + + @Mock + Exchange outExchange; + + @Mock + Message outMessage; + + @Mock + CamelContext camelContext; + + @Mock + RuntimeManager runtimeManager; + + @Test + public void testExecuteInOnlyLocalCamelContext() throws Exception { + + String camelEndpointId = "testCamelRoute"; + String camelRouteUri = "direct://" + camelEndpointId; + + String testReponse = "testResponse"; + + String runtimeManagerId = "testRuntimeManager"; + + when(runtimeManager.getIdentifier()).thenReturn(runtimeManagerId); + + when(producerTemplate.send(eq(camelRouteUri), ArgumentMatchers.any(Exchange.class))).thenReturn(outExchange); + when(producerTemplate.getCamelContext()).thenReturn(camelContext); + + when(camelContext.createProducerTemplate()).thenReturn(producerTemplate); + HeadersMapFactory hmf = new DefaultHeadersMapFactory(); + when(camelContext.getHeadersMapFactory()).thenReturn(hmf); + + // Register the RuntimeManager bound camelcontext. + ServiceRegistry.get().register(runtimeManagerId + "_CamelService", camelContext); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, camelEndpointId); + workItem.setParameter("Request", "someRequest"); + workItem.setDeploymentId("testDeploymentId"); + workItem.setProcessInstanceId(1L); + workItem.setId(1L); + + AbstractCamelWorkItemHandler handler = new InOnlyCamelWorkItemHandler(runtimeManager); + + TestWorkItemManager manager = new TestWorkItemManager(); + handler.executeWorkItem(workItem, + manager); + assertThat(manager.getResults(), is(notNullValue())); + //InOnly does not complete WorkItem. + assertThat(manager.getResults().size(), equalTo(0)); + } +} diff --git a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/InOutCamelWorkItemHandlerTest.java b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/InOutCamelWorkItemHandlerTest.java new file mode 100644 index 00000000000..1277f046edf --- /dev/null +++ b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/workitem/InOutCamelWorkItemHandlerTest.java @@ -0,0 +1,148 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.jbpm.workitem; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.jbpm.JBPMConstants; +import org.apache.camel.impl.DefaultHeadersMapFactory; +import org.apache.camel.spi.HeadersMapFactory; +import org.drools.core.process.instance.impl.WorkItemImpl; +import org.jbpm.process.workitem.core.TestWorkItemManager; +import org.jbpm.services.api.service.ServiceRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.api.runtime.manager.RuntimeManager; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class InOutCamelWorkItemHandlerTest { + + @Mock + ProducerTemplate producerTemplate; + + @Mock + Exchange outExchange; + + @Mock + Message outMessage; + + @Mock + CamelContext camelContext; + + @Mock + RuntimeManager runtimeManager; + + @Test + public void testExecuteInOutGlobalCamelContext() throws Exception { + + String camelEndpointId = "testCamelRoute"; + String camelRouteUri = "direct://" + camelEndpointId; + + String testReponse = "testResponse"; + + when(producerTemplate.send(eq(camelRouteUri), ArgumentMatchers.any(Exchange.class))).thenReturn(outExchange); + when(producerTemplate.getCamelContext()).thenReturn(camelContext); + + when(camelContext.createProducerTemplate()).thenReturn(producerTemplate); + HeadersMapFactory hmf = new DefaultHeadersMapFactory(); + when(camelContext.getHeadersMapFactory()).thenReturn(hmf); + + when(outExchange.getOut()).thenReturn(outMessage); + when(outMessage.getBody()).thenReturn(testReponse); + + ServiceRegistry.get().register("GlobalCamelService", camelContext); + + TestWorkItemManager manager = new TestWorkItemManager(); + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter("CamelEndpointId", camelEndpointId); + workItem.setParameter("Request", "someRequest"); + workItem.setDeploymentId("testDeploymentId"); + workItem.setProcessInstanceId(1L); + workItem.setId(1L); + + AbstractCamelWorkItemHandler handler = new InOutCamelWorkItemHandler(); + + handler.executeWorkItem(workItem, + manager); + assertThat(manager.getResults(), is(notNullValue())); + assertThat(manager.getResults().size(), equalTo(1)); + assertThat(manager.getResults().containsKey(workItem.getId()), is(true)); + Map<String, Object> results = manager.getResults(workItem.getId()); + assertThat(results.size(), equalTo(2)); + assertThat(results.get("Response"), equalTo(testReponse)); + } + + @Test + public void testExecuteInOutLocalCamelContext() throws Exception { + + String camelEndpointId = "testCamelRoute"; + String camelRouteUri = "direct://" + camelEndpointId; + + String testReponse = "testResponse"; + + String runtimeManagerId = "testRuntimeManager"; + + when(runtimeManager.getIdentifier()).thenReturn(runtimeManagerId); + + when(producerTemplate.send(eq(camelRouteUri), ArgumentMatchers.any(Exchange.class))).thenReturn(outExchange); + when(producerTemplate.getCamelContext()).thenReturn(camelContext); + + when(camelContext.createProducerTemplate()).thenReturn(producerTemplate); + HeadersMapFactory hmf = new DefaultHeadersMapFactory(); + when(camelContext.getHeadersMapFactory()).thenReturn(hmf); + + when(outExchange.getOut()).thenReturn(outMessage); + when(outMessage.getBody()).thenReturn(testReponse); + + // Register the RuntimeManager bound camelcontext. + ServiceRegistry.get().register(runtimeManagerId + "_CamelService", camelContext); + + WorkItemImpl workItem = new WorkItemImpl(); + workItem.setParameter(JBPMConstants.CAMEL_ENDPOINT_ID_WI_PARAM, camelEndpointId); + workItem.setParameter("Request", "someRequest"); + workItem.setDeploymentId("testDeploymentId"); + workItem.setProcessInstanceId(1L); + workItem.setId(1L); + + AbstractCamelWorkItemHandler handler = new InOutCamelWorkItemHandler(runtimeManager); + + TestWorkItemManager manager = new TestWorkItemManager(); + handler.executeWorkItem(workItem, + manager); + assertThat(manager.getResults(), is(notNullValue())); + assertThat(manager.getResults().size(), equalTo(1)); + assertThat(manager.getResults().containsKey(workItem.getId()), is(true)); + + Map<String, Object> results = manager.getResults(workItem.getId()); + assertThat(results.size(), equalTo(2)); + assertThat(results.get(JBPMConstants.RESPONSE_WI_PARAM), equalTo(testReponse)); + } + +} ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Create new CamelWIH to integrate with recently added Camel support in > jBPM/KIE-Server > -------------------------------------------------------------------------------------- > > Key: CAMEL-12964 > URL: https://issues.apache.org/jira/browse/CAMEL-12964 > Project: Camel > Issue Type: New Feature > Components: camel-jbpm > Affects Versions: 2.23.0 > Reporter: Duncan Doyle > Assignee: Maciej Swiderski > Priority: Major > Fix For: 2.24.0, 2.23.1 > > > The new camel-jbpm component allows CamelContexts and Routes to be defined on > both a global (KIE-Server) and runtimeManager/deploymentUnit/KJAR level. A > new CamelWorkItemHandler that integrates with these CamelContexts and routes > would allow easy integration with external resources throuch Camel Components > from within a process/case definition. > See: https://issues.jboss.org/browse/JBPM-7995 -- This message was sent by Atlassian JIRA (v7.6.3#76005)