diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiComponent.java b/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiComponent.java index 53d95b342c5f1be9f4d75bef822bf4bdf5d07f7e..bbd9a9361afda1f56fa46d49fe9d8dfc067500e7 100644 --- a/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiComponent.java +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiComponent.java @@ -19,9 +19,23 @@ import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.impl.DefaultComponent; +/** + * This class has been modified to be consistent with the changes to CamelBehavior and its implementations. The set of changes + * significantly increases the flexibility of our Camel integration, as you can either choose one of three "out-of-the-box" modes, + * or you can choose to create your own. Please reference the comments for the "CamelBehavior" class for more information on the + * out-of-the-box implementation class options. + * + * @author Ryan Johnston (@rjfsu), Tijs Rademakers + */ public class ActivitiComponent extends DefaultComponent { private RuntimeService runtimeService; + + private boolean copyVariablesToProperties; + + private boolean copyVariablesToBodyAsMap; + + private boolean copyCamelBodyToBody; public ActivitiComponent() {} @@ -43,6 +57,33 @@ public class ActivitiComponent extends DefaultComponent { @Override protected Endpoint createEndpoint(String s, String s1, Map stringObjectMap) throws Exception { ActivitiEndpoint ae = new ActivitiEndpoint(s, getCamelContext(), runtimeService); + ae.setCopyVariablesToProperties(this.copyVariablesToProperties); + ae.setCopyVariablesToBodyAsMap(this.copyVariablesToBodyAsMap); + ae.setCopyCamelBodyToBody(this.copyCamelBodyToBody); return ae; } + + public boolean isCopyVariablesToProperties() { + return copyVariablesToProperties; + } + + public void setCopyVariablesToProperties(boolean copyVariablesToProperties) { + this.copyVariablesToProperties = copyVariablesToProperties; + } + + public boolean isCopyCamelBodyToBody() { + return copyCamelBodyToBody; + } + + public void setCopyCamelBodyToBody(boolean copyCamelBodyToBody) { + this.copyCamelBodyToBody = copyCamelBodyToBody; + } + + public boolean isCopyVariablesToBodyAsMap() { + return copyVariablesToBodyAsMap; + } + + public void setCopyVariablesToBodyAsMap(boolean copyVariablesToBodyAsMap) { + this.copyVariablesToBodyAsMap = copyVariablesToBodyAsMap; + } } diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiEndpoint.java b/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiEndpoint.java index 8f6be34ebadfa09328a0708e4da0a46439dac8da..d0a05d338edbe9a17f00fc555b31b6fc7d762737 100644 --- a/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiEndpoint.java +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/ActivitiEndpoint.java @@ -17,17 +17,27 @@ import org.activiti.engine.RuntimeService; import org.apache.camel.*; import org.apache.camel.impl.DefaultEndpoint; +/** + * This class has been modified to be consistent with the changes to CamelBehavior and its implementations. The set of changes + * significantly increases the flexibility of our Camel integration, as you can either choose one of three "out-of-the-box" modes, + * or you can choose to create your own. Please reference the comments for the "CamelBehavior" class for more information on the + * out-of-the-box implementation class options. + * + * @author Ryan Johnston (@rjfsu), Tijs Rademakers + */ public class ActivitiEndpoint extends DefaultEndpoint { private RuntimeService runtimeService; private ActivitiConsumer activitiConsumer; - private boolean copyVariablesToProperties = true; + private boolean copyVariablesToProperties; - private boolean copyVariablesToBody = false; + private boolean copyVariablesToBodyAsMap; - private boolean copyVariablesFromProperties = false; + private boolean copyCamelBodyToBody; + + private boolean copyVariablesFromProperties; public ActivitiEndpoint(String uri, CamelContext camelContext, RuntimeService runtimeService) { super(); @@ -48,10 +58,8 @@ public class ActivitiEndpoint extends DefaultEndpoint { throw new RuntimeException("Activiti consumer not defined for " + getEndpointUri()); } activitiConsumer.getProcessor().process(ex); - } - public Producer createProducer() throws Exception { return new ActivitiProducer(this, runtimeService); } @@ -72,14 +80,22 @@ public class ActivitiEndpoint extends DefaultEndpoint { this.copyVariablesToProperties = copyVariablesToProperties; } - public boolean isCopyVariablesToBody() { - return copyVariablesToBody; + public boolean isCopyCamelBodyToBody() { + return copyCamelBodyToBody; } - public void setCopyVariablesToBody(boolean copyVariablesToBody) { - this.copyVariablesToBody = copyVariablesToBody; + public void setCopyCamelBodyToBody(boolean copyCamelBodyToBody) { + this.copyCamelBodyToBody = copyCamelBodyToBody; } + public boolean isCopyVariablesToBodyAsMap() { + return copyVariablesToBodyAsMap; + } + + public void setCopyVariablesToBodyAsMap(boolean copyVariablesToBodyAsMap) { + this.copyVariablesToBodyAsMap = copyVariablesToBodyAsMap; + } + public boolean isCopyVariablesFromProperties() { return copyVariablesFromProperties; } diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehavior.java b/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehavior.java index d0e87c1c2bfcb358735963ee57cf44cbd515dc79..26ae0823d29193cdbcdb743a78f36382bf2bec2f 100644 --- a/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehavior.java +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehavior.java @@ -31,39 +31,61 @@ import org.apache.camel.Exchange; import org.apache.camel.impl.DefaultExchange; import org.apache.commons.lang.StringUtils; -public class CamelBehavior extends BpmnActivityBehavior implements ActivityBehavior { +/** +* This abstract class takes the place of the now-deprecated CamelBehaviour class (which can still be used for legacy compatibility) +* and significantly improves on its flexibility. Additional implementations can be created that change the way in which Activiti +* interacts with Camel per your specific needs. +* +* Three out-of-the-box implementations of CamelBehavior are provided: +* (1) CamelBehaviorDefaultImpl: Works just like CamelBehaviour does; copies variables into and out of Camel as or from properties. +* (2) CamelBehaviorBodyAsMapImpl: Works by copying variables into and out of Camel using a Map object in the body. +* (3) CamelBehaviorCamelBodyImpl: Works by copying a single variable value into Camel as a String body and copying the Camel +* body into that same Activiti variable. The variable in Activiti must be named "camelBody". +* +* The chosen implementation should be set within your ProcessEngineConfiguration. To specify the implementation using Spring, include +* the following line in your configuration file as part of the properties for "org.activiti.spring.SpringProcessEngineConfiguration": +* +* +* +* Note also that the manner in which variables are copied to Activiti from Camel has changed. It will always copy Camel +* properties to the Activiti variable set; they can safely be ignored, of course, if not required. It will conditionally +* copy the Camel body to the "camelBody" variable if it is of type java.lang.String, OR it will copy the Camel body to +* individual variables within Activiti if it is of type Map. +* +* @author Ryan Johnston (@rjfsu), Tijs Rademakers +* @version 5.12 +*/ +public abstract class CamelBehavior extends BpmnActivityBehavior implements ActivityBehavior { private static final long serialVersionUID = 1L; protected Expression camelContext; + protected CamelContext camelContextObj; + protected SpringProcessEngineConfiguration springConfiguration; + + protected abstract void modifyActivitiComponent(ActivitiComponent component); + + protected abstract void copyVariables(Map variables, Exchange exchange, ActivitiEndpoint endpoint); public void execute(ActivityExecution execution) throws Exception { - ProcessEngineConfiguration engineConfiguration = Context.getProcessEngineConfiguration(); - if (engineConfiguration instanceof SpringProcessEngineConfiguration == false) { - throw new ActivitiException("Expecting a Spring process engine configuration for the Activiti Camel module"); - } - - SpringProcessEngineConfiguration springConfiguration = (SpringProcessEngineConfiguration) engineConfiguration; - String camelContextValue = getStringFromField(camelContext, execution); - if (StringUtils.isEmpty(camelContextValue)) { - camelContextValue = springConfiguration.getDefaultCamelContext(); - } + setAppropriateCamelContext(execution); + //Retrieve the ActivitiComponent object. + ActivitiComponent component = camelContextObj.getComponent("activiti", ActivitiComponent.class); + modifyActivitiComponent(component); - ActivitiEndpoint endpoint = createEndpoint(execution, springConfiguration, camelContextValue); - Exchange exchange = createExchange(execution, endpoint, springConfiguration, camelContextValue); + ActivitiEndpoint endpoint = createEndpoint(execution); + Exchange exchange = createExchange(execution, endpoint); endpoint.process(exchange); execution.setVariables(ExchangeUtils.prepareVariables(exchange, endpoint)); performDefaultOutgoingBehavior(execution); - } - - private ActivitiEndpoint createEndpoint(ActivityExecution execution, SpringProcessEngineConfiguration springConfiguration, String camelContext) { + protected ActivitiEndpoint createEndpoint(ActivityExecution execution) { String uri = "activiti://" + getProcessDefinitionKey(execution) + ":" + execution.getActivity().getId(); - return getEndpoint(getContext(springConfiguration, camelContext), uri); + return getEndpoint(uri); } - private ActivitiEndpoint getEndpoint(CamelContext ctx, String key) { - for (Endpoint e : ctx.getEndpoints()) { + protected ActivitiEndpoint getEndpoint(String key) { + for (Endpoint e : camelContextObj.getEndpoints()) { if (e.getEndpointKey().equals(key) && (e instanceof ActivitiEndpoint)) { return (ActivitiEndpoint) e; } @@ -71,37 +93,72 @@ public class CamelBehavior extends BpmnActivityBehavior implements ActivityBehav throw new RuntimeException("Activiti endpoint not defined for " + key); } - private CamelContext getContext(SpringProcessEngineConfiguration springConfiguration, String camelContext) { - Object ctx = springConfiguration.getApplicationContext().getBean(camelContext); - if (ctx == null || ctx instanceof CamelContext == false) { - throw new RuntimeException("Could not find camel context " + camelContext); - } - return (CamelContext) ctx; - } - - - private Exchange createExchange(ActivityExecution activityExecution, ActivitiEndpoint endpoint, - SpringProcessEngineConfiguration springConfiguration, String camelContext) { - - Exchange ex = new DefaultExchange(getContext(springConfiguration, camelContext)); + protected Exchange createExchange(ActivityExecution activityExecution, ActivitiEndpoint endpoint) { + Exchange ex = new DefaultExchange(camelContextObj); ex.setProperty(ActivitiProducer.PROCESS_ID_PROPERTY, activityExecution.getProcessInstanceId()); Map variables = activityExecution.getVariables(); - if (endpoint.isCopyVariablesToProperties()) { - for (Map.Entry var : variables.entrySet()) { - ex.setProperty(var.getKey(), var.getValue()); - } + copyVariables(variables, ex, endpoint); + return ex; + } + + protected void copyVariablesToProperties(Map variables, Exchange exchange) { + for (Map.Entry var : variables.entrySet()) { + exchange.setProperty(var.getKey(), var.getValue()); } - if (endpoint.isCopyVariablesToBody()) { - ex.getIn().setBody(new HashMap(variables)); + } + + protected void copyVariablesToBodyAsMap(Map variables, Exchange exchange) { + exchange.getIn().setBody(new HashMap(variables)); + } + + protected void copyVariablesToBody(Map variables, Exchange exchange) { + Object camelBody = variables.get("camelBody"); + if(camelBody != null) { + exchange.getIn().setBody(camelBody); } - return ex; } - private String getProcessDefinitionKey(ActivityExecution execution) { + protected String getProcessDefinitionKey(ActivityExecution execution) { String id = execution.getActivity().getProcessDefinition().getId(); return id.substring(0, id.indexOf(":")); } + protected void setAppropriateCamelContext(ActivityExecution execution) { + //Check to see if the springConfiguration has been set. If not, set it. + if (springConfiguration == null) { + //Get the ProcessEngineConfiguration object. + ProcessEngineConfiguration engineConfiguration = Context.getProcessEngineConfiguration(); + + //Convert it to a SpringProcessEngineConfiguration. If this doesn't work, throw a RuntimeException. + // (ActivitiException extends RuntimeException.) + try { + springConfiguration = (SpringProcessEngineConfiguration) engineConfiguration; + } catch (Exception e) { + throw new ActivitiException("Expecting a SpringProcessEngineConfiguration for the Activiti Camel module.", e); + } + } + + //Get the appropriate String representation of the CamelContext object from ActivityExecution (if available). + String camelContextValue = getStringFromField(camelContext, execution); + + //If the String representation of the CamelContext object from ActivityExecution is empty, use the default. + if (StringUtils.isEmpty(camelContextValue) && camelContextObj != null) { + //No processing required. No custom CamelContext & the default is already set. + } + else { + if (StringUtils.isEmpty(camelContextValue) && camelContextObj == null) { + camelContextValue = springConfiguration.getDefaultCamelContext(); + } + + //Get the CamelContext object and set the super's member variable. + Object ctx = springConfiguration.getApplicationContext().getBean(camelContextValue); + if (ctx == null || ctx instanceof CamelContext == false) { + throw new ActivitiException("Could not find CamelContext named " + camelContextValue + "."); + } + camelContextObj = (CamelContext)ctx; + } + } + protected String getStringFromField(Expression expression, DelegateExecution execution) { if (expression != null) { Object value = expression.getValue(execution); diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehaviour.java b/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehaviour.java index 5c7711271b5c2f2d13ae3320cc961edd240518f6..da2eaab59a80362d58b8874a79a0d9a6a55355b5 100644 --- a/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehaviour.java +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/CamelBehaviour.java @@ -25,8 +25,11 @@ import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.impl.DefaultExchange; +@Deprecated public class CamelBehaviour extends BpmnActivityBehavior implements ActivityBehavior { + private static final long serialVersionUID = 1L; + private Collection contextProviders; public CamelBehaviour(Collection camelContext) { @@ -76,7 +79,7 @@ public class CamelBehaviour extends BpmnActivityBehavior implements ActivityBeha ex.setProperty(var.getKey(), var.getValue()); } } - if (endpoint.isCopyVariablesToBody()) { + if (endpoint.isCopyVariablesToBodyAsMap()) { ex.getIn().setBody(new HashMap(variables)); } return ex; diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/ExchangeUtils.java b/modules/activiti-camel/src/main/java/org/activiti/camel/ExchangeUtils.java index bfa21c38f63cc443d9f8fd5feb5e4dae742ad19d..9399e740234882576f3b23c3ed7cc7d538a3bef3 100644 --- a/modules/activiti-camel/src/main/java/org/activiti/camel/ExchangeUtils.java +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/ExchangeUtils.java @@ -12,24 +12,52 @@ */ package org.activiti.camel; -import org.apache.camel.Exchange; - import java.util.HashMap; import java.util.Map; +import org.apache.camel.Exchange; + +/** + * This class contains one method - prepareVariables - that is used to copy variables from Camel into Activiti. + * + * @author Ryan Johnston (@rjfsu), Tijs Rademakers + */ public class ExchangeUtils { - static Map prepareVariables(Exchange exchange, ActivitiEndpoint activitiEndpoint) { - Map ret = new HashMap(); + /** + * Copies variables from Camel into Activiti. + * + * This method will conditionally copy the Camel body to the "camelBody" variable if it is of type java.lang.String, OR it will copy the Camel body to + * individual variables within Activiti if it is of type Map. + * If the copyVariablesFromProperties parameter is set on the endpoint, the properties are copied instead + * + * @param exchange The Camel Exchange object + * @param activitiEndpoint The ActivitiEndpoint implementation + * @return A Map containing all of the variables to be used in Activiti + */ + + public static Map prepareVariables(Exchange exchange, ActivitiEndpoint activitiEndpoint) { boolean shouldReadFromProperties = activitiEndpoint.isCopyVariablesFromProperties(); - Map m = shouldReadFromProperties ? exchange.getProperties() : exchange.getIn().getBody(Map.class); - if (m != null) { - for (Map.Entry e : m.entrySet()) { - if (e.getKey() instanceof String) { - ret.put((String) e.getKey(), e.getValue()); + Map camelVarMap = null; + + if (shouldReadFromProperties) { + camelVarMap = exchange.getProperties(); + } else { + camelVarMap = new HashMap(); + Object camelBody = exchange.getIn().getBody(); + if(camelBody instanceof String) { + camelVarMap.put("camelBody", camelBody); + } + else if(camelBody instanceof Map) { + Map camelBodyMap = (Map)camelBody; + for (@SuppressWarnings("rawtypes") Map.Entry e : camelBodyMap.entrySet()) { + if (e.getKey() instanceof String) { + camelVarMap.put((String) e.getKey(), e.getValue()); + } } } } - return ret; + + return camelVarMap; } } diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorBodyAsMapImpl.java b/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorBodyAsMapImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1398d351c93cb8f673cb295a5f5f588b25e27085 --- /dev/null +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorBodyAsMapImpl.java @@ -0,0 +1,53 @@ +/* Licensed 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.activiti.camel.impl; + +import java.util.Map; + +import org.activiti.camel.ActivitiComponent; +import org.activiti.camel.ActivitiEndpoint; +import org.activiti.camel.CamelBehavior; +import org.apache.camel.Exchange; + +/** + * This implementation of the CamelBehavior abstract class works by copying variables into Camel using a + * Map object in the Camel Exchange body. + * + * @author Ryan Johnston (@rjfsu), Tijs Rademakers + */ +public class CamelBehaviorBodyAsMapImpl extends CamelBehavior { + + private static final long serialVersionUID = 1L; + + @Override + protected void modifyActivitiComponent(ActivitiComponent component) { + //Set the copy method for new endpoints created using this component. + component.setCopyVariablesToProperties(false); + component.setCopyVariablesToBodyAsMap(true); + component.setCopyCamelBodyToBody(false); + } + + @Override + protected void copyVariables(Map variables, Exchange exchange, ActivitiEndpoint endpoint) { + if (endpoint.isCopyVariablesToProperties()) { + copyVariablesToBody(variables, exchange); + } else if (endpoint.isCopyVariablesToProperties()) { + copyVariablesToProperties(variables, exchange); + } else { + copyVariablesToBodyAsMap(variables, exchange); + } + } + +} + diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorCamelBodyImpl.java b/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorCamelBodyImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..691f8b1c179d0efaa6c0d391057e45f0e2af657c --- /dev/null +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorCamelBodyImpl.java @@ -0,0 +1,53 @@ +/* Licensed 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.activiti.camel.impl; + +import java.util.Map; + +import org.activiti.camel.ActivitiComponent; +import org.activiti.camel.ActivitiEndpoint; +import org.activiti.camel.CamelBehavior; +import org.apache.camel.Exchange; + +/** + * This implementation of the CamelBehavior abstract class works by copying a single variable value into the Camel + * Exchange body. The variable must be named "camelBody" to be copied into the Camel Exchange body on the producer + * side of the transfer (i.e. when handing control from Activiti to Camel). + * + * @author Ryan Johnston (@rjfsu), Tijs Rademakers + */ +public class CamelBehaviorCamelBodyImpl extends CamelBehavior { + + private static final long serialVersionUID = 1L; + + @Override + protected void modifyActivitiComponent(ActivitiComponent component) { + //Set the copy method for new endpoints created using this component. + component.setCopyVariablesToProperties(false); + component.setCopyVariablesToBodyAsMap(false); + component.setCopyCamelBodyToBody(true); + } + + @Override + protected void copyVariables(Map variables, Exchange exchange, ActivitiEndpoint endpoint) { + if (endpoint.isCopyVariablesToBodyAsMap()) { + copyVariablesToBodyAsMap(variables, exchange); + } else if (endpoint.isCopyVariablesToProperties()) { + copyVariablesToProperties(variables, exchange); + } else { + copyVariablesToBody(variables, exchange); + } + } +} + diff --git a/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorDefaultImpl.java b/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorDefaultImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..218131ab9ee3c403c2ba3f7a59e4fa1f75777e85 --- /dev/null +++ b/modules/activiti-camel/src/main/java/org/activiti/camel/impl/CamelBehaviorDefaultImpl.java @@ -0,0 +1,51 @@ +/* Licensed 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.activiti.camel.impl; + +import java.util.Map; + +import org.activiti.camel.ActivitiComponent; +import org.activiti.camel.ActivitiEndpoint; +import org.activiti.camel.CamelBehavior; +import org.apache.camel.Exchange; + +/** + * This implementation of the CamelBehavior abstract class works just like CamelBehaviour does; it copies variables + * into Camel as properties. + * + * @author Ryan Johnston (@rjfsu), Tijs Rademakers + */ +public class CamelBehaviorDefaultImpl extends CamelBehavior { + + private static final long serialVersionUID = 003L; + + @Override + protected void modifyActivitiComponent(ActivitiComponent component) { + //Set the copy method for new endpoints created using this component. + component.setCopyVariablesToProperties(true); + component.setCopyVariablesToBodyAsMap(false); + component.setCopyCamelBodyToBody(false); + } + + @Override + protected void copyVariables(Map variables, Exchange exchange, ActivitiEndpoint endpoint) { + if (endpoint.isCopyVariablesToBodyAsMap()) { + copyVariablesToBodyAsMap(variables, exchange); + } else if (endpoint.isCopyCamelBodyToBody()) { + copyVariablesToBody(variables, exchange); + } else { + copyVariablesToProperties(variables, exchange); + } + } +} diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/CamelVariableBodyMapTest.java b/modules/activiti-camel/src/test/java/org/activiti/camel/CamelVariableBodyMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d640c4fd7f5b86bcdec12271b9508037af605f5f --- /dev/null +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/CamelVariableBodyMapTest.java @@ -0,0 +1,44 @@ +package org.activiti.camel; + +import java.util.HashMap; +import java.util.Map; + +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.Task; +import org.activiti.engine.test.Deployment; +import org.activiti.spring.impl.test.SpringActivitiTestCase; +import org.apache.camel.CamelContext; +import org.apache.camel.component.mock.MockEndpoint; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration("classpath:camel-activiti-context.xml") +public class CamelVariableBodyMapTest extends SpringActivitiTestCase { + + MockEndpoint service1; + + public void setUp() { + CamelContext ctx = applicationContext.getBean(CamelContext.class); + service1 = (MockEndpoint) ctx.getEndpoint("mock:serviceBehavior"); + service1.reset(); + } + + @Deployment(resources = {"process/HelloCamelBodyMap.bpmn20.xml"}) + public void testCamelBody() throws Exception { + Map varMap = new HashMap(); + varMap.put("camelBody", "hello world"); + service1.expectedBodiesReceived(varMap); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("HelloCamel", varMap); + //Ensure that the variable is equal to the expected value. + assertEquals("hello world", runtimeService.getVariable(processInstance.getId(), "camelBody")); + service1.assertIsSatisfied(); + + Task task = taskService.createTaskQuery().singleResult(); + + //Ensure that the name of the task is correct. + assertEquals("Hello Task", task.getName()); + + //Complete the task. + taskService.complete(task.getId()); + } + +} diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/CamelVariableBodyTest.java b/modules/activiti-camel/src/test/java/org/activiti/camel/CamelVariableBodyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c3aecc42fe4c4c637c1e9d58e1d17973eab9dcbb --- /dev/null +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/CamelVariableBodyTest.java @@ -0,0 +1,44 @@ +package org.activiti.camel; + +import java.util.HashMap; +import java.util.Map; + +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.Task; +import org.activiti.engine.test.Deployment; +import org.activiti.spring.impl.test.SpringActivitiTestCase; +import org.apache.camel.CamelContext; +import org.apache.camel.component.mock.MockEndpoint; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration("classpath:camel-activiti-context.xml") +public class CamelVariableBodyTest extends SpringActivitiTestCase { + + MockEndpoint service1; + + public void setUp() { + CamelContext ctx = applicationContext.getBean(CamelContext.class); + service1 = (MockEndpoint) ctx.getEndpoint("mock:serviceBehavior"); + service1.reset(); + } + + @Deployment(resources = {"process/HelloCamelBody.bpmn20.xml"}) + public void testCamelBody() throws Exception { + service1.expectedBodiesReceived("hello world"); + Map varMap = new HashMap(); + varMap.put("camelBody", "hello world"); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("HelloCamel", varMap); + //Ensure that the variable is equal to the expected value. + assertEquals("hello world", runtimeService.getVariable(processInstance.getId(), "camelBody")); + service1.assertIsSatisfied(); + + Task task = taskService.createTaskQuery().singleResult(); + + //Ensure that the name of the task is correct. + assertEquals("Hello Task", task.getName()); + + //Complete the task. + taskService.complete(task.getId()); + } + +} diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/SimpleProcessTest.java b/modules/activiti-camel/src/test/java/org/activiti/camel/SimpleProcessTest.java index ec7071ad1bc531283a183049d55788b010ac5e61..bf7388186c09d1b79c66391669065c27c168d769 100644 --- a/modules/activiti-camel/src/test/java/org/activiti/camel/SimpleProcessTest.java +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/SimpleProcessTest.java @@ -47,7 +47,6 @@ public class SimpleProcessTest extends SpringActivitiTestCase { String instanceId = (String) tpl.requestBody("direct:start", Collections.singletonMap("var1", "ala")); - tpl.sendBodyAndProperty("direct:receive", null, ActivitiProducer.PROCESS_ID_PROPERTY, instanceId); assertProcessEnded(instanceId); @@ -67,7 +66,6 @@ public class SimpleProcessTest extends SpringActivitiTestCase { MockEndpoint me = (MockEndpoint) ctx.getEndpoint("mock:service1"); me.expectedBodiesReceived("ala"); - tpl.sendBodyAndProperty("direct:start", Collections.singletonMap("var1", "ala"), ActivitiProducer.PROCESS_KEY_PROPERTY, "key1"); String instanceId = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey("key1") diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/TestJoinDelegate.java b/modules/activiti-camel/src/test/java/org/activiti/camel/TestJoinDelegate.java index 9e71c950fb00349cf134929fdf5ab90d10851adf..792b80dc8740075ea569a1e34162df5229c4f73b 100644 --- a/modules/activiti-camel/src/test/java/org/activiti/camel/TestJoinDelegate.java +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/TestJoinDelegate.java @@ -7,7 +7,7 @@ public class TestJoinDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { - System.out.println("testing join delegate"); + // dummy task } } diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/route/AsyncCamelRoute.java b/modules/activiti-camel/src/test/java/org/activiti/camel/route/AsyncCamelRoute.java index c0641641f67700d7e3e9f7ddbee2d17f69bc78c5..70b210bfeb28c2199e6ab436fa1338ed0e37ba22 100644 --- a/modules/activiti-camel/src/test/java/org/activiti/camel/route/AsyncCamelRoute.java +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/route/AsyncCamelRoute.java @@ -20,10 +20,10 @@ public class AsyncCamelRoute extends RouteBuilder { @Override public void configure() throws Exception { - from("activiti:asyncCamelProcess:serviceTaskAsync1?copyVariablesToProperties=true").setHeader("destination", constant("activiti:asyncCamelProcess:receive1")).to("seda:asyncQueue"); + from("activiti:asyncCamelProcess:serviceTaskAsync1").setHeader("destination", constant("activiti:asyncCamelProcess:receive1")).to("seda:asyncQueue"); from("seda:asyncQueue").to("bean:sleepBean?method=sleep").to("seda:receiveQueue"); - from("activiti:asyncCamelProcess:serviceTaskAsync2?copyVariablesToProperties=true").setHeader("destination", constant("activiti:asyncCamelProcess:receive2")).to("seda:asyncQueue2"); + from("activiti:asyncCamelProcess:serviceTaskAsync2").setHeader("destination", constant("activiti:asyncCamelProcess:receive2")).to("seda:asyncQueue2"); from("seda:asyncQueue2").to("bean:sleepBean?method=sleep").to("seda:receiveQueue"); from("seda:receiveQueue").recipientList(header("destination")); diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/route/CamelBehaviorRoute.java b/modules/activiti-camel/src/test/java/org/activiti/camel/route/CamelBehaviorRoute.java new file mode 100644 index 0000000000000000000000000000000000000000..cec3e3c5c80f19493c933e34bb84a457ae604192 --- /dev/null +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/route/CamelBehaviorRoute.java @@ -0,0 +1,17 @@ +package org.activiti.camel.route; + +import org.apache.camel.LoggingLevel; +import org.apache.camel.spring.SpringRouteBuilder; +import org.springframework.stereotype.Component; + +@Component +public class CamelBehaviorRoute extends SpringRouteBuilder { + + public void configure() { + + from("activiti:HelloCamel:serviceTask1") + .log(LoggingLevel.INFO,"Received message on service task") + .to("mock:serviceBehavior"); + } + +} diff --git a/modules/activiti-camel/src/test/java/org/activiti/camel/route/SampleCamelRoute.java b/modules/activiti-camel/src/test/java/org/activiti/camel/route/SampleCamelRoute.java index 59e1cb3fa648d228341cb02cb7a4d77e40e6e19d..25474e9da271f001d27b28bb34b24940ac76d3b3 100644 --- a/modules/activiti-camel/src/test/java/org/activiti/camel/route/SampleCamelRoute.java +++ b/modules/activiti-camel/src/test/java/org/activiti/camel/route/SampleCamelRoute.java @@ -24,7 +24,7 @@ public class SampleCamelRoute extends RouteBuilder { .to("mock:service1").setProperty("var2").constant("var2") .setBody().properties(); - from("activiti:camelProcess:serviceTask2?copyVariablesToBody=true") + from("activiti:camelProcess:serviceTask2?copyVariablesToBodyAsMap=true") .to("mock:service2"); diff --git a/modules/activiti-camel/src/test/resources/process/HelloCamelBody.bpmn20.xml b/modules/activiti-camel/src/test/resources/process/HelloCamelBody.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..30d405b20d9935c0a859682ed7b95f3456381aee --- /dev/null +++ b/modules/activiti-camel/src/test/resources/process/HelloCamelBody.bpmn20.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/activiti-camel/src/test/resources/process/HelloCamelBodyMap.bpmn20.xml b/modules/activiti-camel/src/test/resources/process/HelloCamelBodyMap.bpmn20.xml new file mode 100644 index 0000000000000000000000000000000000000000..49d471a78073893cdfe3783473aff430fbb7071c --- /dev/null +++ b/modules/activiti-camel/src/test/resources/process/HelloCamelBodyMap.bpmn20.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/activiti-camel/src/test/resources/spring-camel-activiti-context.xml b/modules/activiti-camel/src/test/resources/spring-camel-activiti-context.xml index 65e81c084f795cd29cbc64fb96bd552712b4e963..b6bed21fb4337562d74c4de072136b9ffd4e748c 100644 --- a/modules/activiti-camel/src/test/resources/spring-camel-activiti-context.xml +++ b/modules/activiti-camel/src/test/resources/spring-camel-activiti-context.xml @@ -51,7 +51,7 @@ - + diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/factory/DefaultActivityBehaviorFactory.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/factory/DefaultActivityBehaviorFactory.java index 909b4d72d001bb7129035b3a844050665a090f75..c416ad212fb4ac7fa0d2cf282d7c0bc9acb20cd2 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/factory/DefaultActivityBehaviorFactory.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/factory/DefaultActivityBehaviorFactory.java @@ -198,8 +198,25 @@ public class DefaultActivityBehaviorFactory extends AbstractBehaviorFactory impl protected ActivityBehavior createCamelActivityBehavior(Task task, List fieldExtensions, BpmnModel bpmnModel) { try { - - Class< ? > theClass = Class.forName("org.activiti.camel.CamelBehavior"); + Class< ? > theClass = null; + FieldExtension behaviorExtension = null; + for (FieldExtension fieldExtension : fieldExtensions) { + if ("camelBehaviorClass".equals(fieldExtension.getFieldName()) && StringUtils.isNotEmpty(fieldExtension.getStringValue())) { + theClass = Class.forName(fieldExtension.getStringValue()); + behaviorExtension = fieldExtension; + break; + } + } + + if (behaviorExtension != null) { + fieldExtensions.remove(behaviorExtension); + } + + if (theClass == null) { + // Default Camel behavior class + theClass = Class.forName("org.activiti.camel.impl.CamelBehaviorDefaultImpl"); + } + List fieldDeclarations = createFieldDeclarations(fieldExtensions); return (ActivityBehavior) ClassDelegate.instantiateDelegate(theClass, fieldDeclarations); diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminCompletedInstancesPanel.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminCompletedInstancesPanel.java index 4384222d0f6a6120d8ef1789f7bbdb309c9a50a1..a7bd532431618ae38071b92e00d04221163bc2c8 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminCompletedInstancesPanel.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminCompletedInstancesPanel.java @@ -152,6 +152,10 @@ public class AdminCompletedInstancesPanel extends DetailPanel { } else { ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult(); + if (definition == null) { + // this process has a missing definition - skip + continue; + } managementDefinition = new ManagementProcessDefinition(); managementDefinition.processDefinition = definition; managementDefinition.runningInstances = new ArrayList(); diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminRunningInstancesPanel.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminRunningInstancesPanel.java index eb2cd63145e2db6fa971ffd471fc0b22922169a6..3a8511e2efcc2371a0e0c66b026228cc11f90688 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminRunningInstancesPanel.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/admin/AdminRunningInstancesPanel.java @@ -154,6 +154,10 @@ public class AdminRunningInstancesPanel extends DetailPanel { } else { ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult(); + if (definition == null) { + // this process has a missing definition - skip + continue; + } managementDefinition = new ManagementProcessDefinition(); managementDefinition.processDefinition = definition; managementDefinition.runningInstances = new ArrayList(); diff --git a/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml b/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml index dda6319f387f42227196cbc2a86ef8d1ec5c45f9..017e26f907e311109a5b937cf7e3ba60deb7ab32 100644 --- a/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml +++ b/userguide/src/en/chapters/ch07b-BPMN-Constructs.xml @@ -4210,11 +4210,12 @@ public class AsyncCamelRoute extends RouteBuilder { } Note the from endpoint definition "activiti:asyncCamelProcess:serviceTaskAsync1" where activiti relates to the Activiti Camel component. asyncCamelProcess refers to the process definition key of the process definition. And serviceTaskAsync1 relates to the identifier of the Camel task. The process variables can be copied to the body or the properties of the Camel payload. - In this example the variables are copied as message properties. copyVariablesToBody will copy the variables to the body of the Camel message. + In this example the variables are copied as message properties (the default). copyVariablesToBodyAsMap=true will copy the variables to the body of the Camel message in a Map instance. + copyCamelBodyToBody=true will copy the camelBody process variable to the body of the Camel message In this example you can also see that a Camel message can be sent to a receive task of an Activiti process instance. In this example a bit of additional Camel logic is used to send the Camel message to the receive task that's defined in the message header destination property. But eventually the message will be sent to the receive1 or receive2 receive tasks. - By default the message body of the Camel message is expected as a Map and all Map entries will be copied to the Activiti execution. When defining the copyVariablesToProperties=true option the message properties are - copied to the Activiti execution. + By default the message body of the Camel message is expected as a Map (all Map entries will be copied to the Activiti execution) or as a String that will be copied to the camelBody process variable. + When defining the copyVariablesToProperties=true option the message properties are copied to the Activiti execution. @@ -4230,6 +4231,19 @@ public class AsyncCamelRoute extends RouteBuilder { <extensionElements> <activiti:field name="camelContext" stringValue="customCamelContext" /> </extensionElements> +</serviceTask> + + + + You can also override the default Camel behavior class (org.activiti.camel.impl.CamelBehaviorDefaultImpl). This can be handy to customize the Camel logic or to change the default behavior of copying the process + variables to something else. The Activiti Camel module provide two additional Camel behavior classes, CamelBehaviorBodyAsMapImpl and CamelBehaviorCamelBodyImpl. CamelBehaviorBodyAsMapImpl copies the process variables + to a Map instance in the Camel message body by default (remember that you can override this on the endpoint using for example copyVariablesToProperties=true). CamelBehaviorCamelBodyImpl expects a camelBody process variable + and copies it to the Camel message body. The default Camel behavior class can be overriden by using the following field definition: + +<serviceTask id="serviceTask1" activiti:type="camel"> + <extensionElements> + <activiti:field name="camelBehaviorClass" stringValue="org.activiti.camel.impl.CamelBehaviorCamelBodyImpl" /> + </extensionElements> </serviceTask>