The Camel task allows you to send and receive messages to and from Camel, thus enhancing the integration function of Flowable. Note that the Camel task is not an official task of the BPMN 2.0 specification (so there is no special icon). Therefore, in the Flowable, the Camel task is implemented as a dedicated service task. Also note that you must include the Flowable camera module in your project to use the camera task function.
1. Define a camel task
The camel task is implemented as a dedicated service task, and by setting the task of the service of the type of "Camel" defined.
<serviceTask id="sendCamel" flowable:type="camel">
The process definition itself only needs the hump type definition on the service task. The integration logic is all delegated to the Camel container. By default, the Flowable engine looks for the camelContext bean in the Spring container. The camelContext bean defines the Camel route to be loaded by the Camel container. In the following example, the route is loaded from a specific Java package, but you can also define the route directly in the Spring configuration itself.
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring"> <packageScan> <package>org.flowable.camel.route</package> </packageScan> </camelContext>
For more documents about Camel routes, you can find them on the Camel website. The basic concept is demonstrated by the following small samples. In the first example, we will perform the simplest form of the Camel call from the Flowable workflow. We call it SimpleCamelCall.
If you want to define multiple Camel context beans or use different bean names, you can override them in the Camel task definition, as shown below:
<serviceTask id="serviceTask1" flowable:type="camel"> <extensionElements> <flowable:field name="camelContext" stringValue="customCamelContext" /> </extensionElements> </serviceTask>
2. Simple camel call example
All the files related to this example can be found in the org.flowable.camel.examples.simpleCamelCall package of the process module. The goal is to activate a specific camel route. First, we need a Spring context that contains the routes described earlier. The following is the purpose:
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring"> <packageScan> <package>org.flowable.camel.examples.simpleCamelCall</package> </packageScan> </camelContext>
public class SimpleCamelCallRoute extends RouteBuilder { @Override public void configure() throws Exception { from("flowable:SimpleCamelCallProcess:simpleCall").to("log:org.flowable.camel.examples.SimpleCamelCall"); } }
The route only records the message body, and there is no more. Note the format from the endpoint. It consists of three parts:
Endpoint URL section | describe |
---|---|
mobility | Refers to the engine endpoint |
The name of the SimpleCamelCallProcess process process | |
simpleCall | The name of the service in the process |
OK, our route has been correctly configured and can be accessed by camels. Now it's part of the workflow. The workflow is as follows:
<process id="SimpleCamelCallProcess"> <startEvent id="start"/> <sequenceFlow id="flow1" sourceRef="start" targetRef="simpleCall"/> <serviceTask id="simpleCall" flowable:type="camel"/> <sequenceFlow id="flow2" sourceRef="simpleCall" targetRef="end"/> <endEvent id="end"/> </process>
3. Examples of table tennis
Our example works, but there is no real transfer between Camel and flow, so there are not many advantages. In this example, we try to send data to and receive data from camera. We send a string, and Camel concatenates it and returns the result. The sender part is trivial. We send our message to the Camel task in the form of variables. This is our caller ID code:
@Deployment public void testPingPong() { Map<String, Object> variables = new HashMap<String, Object>(); variables.put("input", "Hello"); Map<String, String> outputMap = new HashMap<String, String>(); variables.put("outputMap", outputMap); runtimeService.startProcessInstanceByKey("PingPongProcess", variables); assertEquals(1, outputMap.size()); assertNotNull(outputMap.get("outputValue")); assertEquals("Hello World", outputMap.get("outputValue")); }
The variable "input" is actually the input of the Camel path, and outputMap is used to capture the results from Camel. This process may be as follows:
<process id="PingPongProcess"> <startEvent id="start"/> <sequenceFlow id="flow1" sourceRef="start" targetRef="ping"/> <serviceTask id="ping" flowable:type="camel"/> <sequenceFlow id="flow2" sourceRef="ping" targetRef="saveOutput"/> <serviceTask id="saveOutput" flowable:class="org.flowable.camel.examples.pingPong.SaveOutput" /> <sequenceFlow id="flow3" sourceRef="saveOutput" targetRef="end"/> <endEvent id="end"/> </process>
Note that the SaveOutput service task stores the value of the "Output" variable from the context into the previously mentioned OutputMap. Now we must know how the variable is sent to Camel, and then return. The concept of Camel behavior plays a role. The way variables are passed to camels can be configured through CamelBehavior. Here we use the default values in our sample, followed by other short descriptions. Using similar code, you can configure the required Camel behavior:
<serviceTask id="serviceTask1" flowable:type="camel"> <extensionElements> <flowable:field name="camelBehaviorClass" stringValue="org.flowable.camel.impl.CamelBehaviorCamelBodyImpl" /> </extensionElements> </serviceTask>
If you don't give specific behavior, org.flowable.camel.impl.CamelBehaviorDefaultImpl will be set. This behavior copies variables to camels with the same name
Sex. In return, regardless of the selected behavior, if the camel message body is a mapping, each element of it is copied as a variable, otherwise the whole object is copied into a specific variable named "camelBody". Knowing this, this camel route ends our second example:
public void configure() throws Exception { from("flowable:PingPongProcess:ping").transform().simple("${property.input} World"); }
In this route, the string "world" is connected to the end of the attribute named "input", and the result will be set in the message body. You can access it by checking the "camelBody" variable in the Java service task and copying it to the "outputMap". Now let's look at an example of its default behavior, and let's look at other possibilities. When each camera route is started, the process instance ID is copied to the camera attribute with a specific name of "PROCESS_ID_PROPERTY". Used later to associate process instances and Camel routes. Moreover, it can be used in Camel routes.
Three different behaviors are available in Flowable. Behavior can be overridden by a specific phrase in the routing URL. The following is an example of overriding a defined behavior in a URL:
from("flowable:asyncCamelProcess:serviceTaskAsync2?copyVariablesToProperties=true").
The following table provides an overview of three available camel behaviors:
behavior | In URL | describe |
---|---|---|
CamelBehaviorDefaultImpl | copyVariablesToProperties | Copy flowable variables as attributes |
CamelBehaviorCamelBodyImpl | copyCamelBodyToBody | Only the Flowable variable named "camelBody" is copied as the body of the Camel message |
CamelBehaviorBodyAsMapImpl | copyVariablesToBodyAsMap | Copy all the Flowable variables into the map as the Camel message body |
The above table describes how Flowable variables will be passed to camels. The following table describes how camel variables are returned to Flowable. This can only be configured in the routing URL.
website | describe |
---|---|
default | If the camel body is a mapping, copy each element as a Flowable variable, otherwise copy the whole camel body as a "camelBody" rheological variable |
copyVariablesFromProperties | Copy the Camel attribute as a Flowable variable with the same name |
copyCamelBodyToBodyAsString | As for the default, if the camelBody is not a map, first convert it to String, and then copy it to the "camelBody" |
copyVariablesFromHeader | In addition, copy the camera header file to the Flowable variable with the same name |
4. Return variable
The above mentioned content about transferring variables only applies to the initial end of variable transmission, whether you flow from camel or from camel to camel.
It should be noted that due to the special non blocking behavior of Flowable, variables will not be automatically returned from Flowable to camel. To do this, you can use special syntax. Camel routing URL can have one or more parameters in the format of var.return.someVariableName. All variables with names equal to one of these parameters (without the var.return part) will be treated as output variables and copied as camel attributes with the same name.
For example, in the following routes:
From ("direct: start") to ("liquidity: process var.return.exampleVar?") to ("simulation: results");
A variable with the name exampleVar "flow" will be treated as an output variable and copied back as a camel attribute with the same name.
5. Asynchronous Ping Pong example
All previous examples are synchronized. The process instance waits until the route ends and returns. In some cases, we may need a Flowable process instance to continue. For this purpose, the asynchronous capability of Camel service tasks is useful. You can use this feature by setting the async property of the Camel service task to true.
<serviceTask id="serviceAsyncPing" flowable:type="camel" flowable:async="true"/>
By setting this function, the specified Camel route is activated asynchronously by the Flowable job executor. When a queue is defined in the Camel path, the Flowable process instance will continue the activities defined after the Camel service task in the process definition. The Camel route will execute completely asynchronously with the process execution. If you want to wait for a response from a Camel service task somewhere in the process definition, you can use receive task.
<receiveTask id="receiveAsyncPing" name="Wait State" />
The process instance will wait until a signal is received, for example, from the Camel. In Camel, you can send a signal to the process instance by sending a message to the appropriate Flowable endpoint.
from("flowable:asyncPingProcess:serviceAsyncPing").to("flowable:asyncPingProcess:receiveAsyncPing");
- Constant string "flow"
- Process name
- Receive task name
6. Instantiate workflow from camel route
In all the previous examples, the Flowable process instance is started first, and the Camel process is started from the process instance. You can also process transactions in other ways, starting or invoking process instances from routes that have been started. This is very similar to sending and receiving tasks. This is an example route:
from("direct:start").to("flowable:camelProcess");
As you can see, the URL has two parts: the first is the constant string "flowable", and the second is the name of the process definition. Obviously, the process definition should have been deployed to the flowable engine.
You can also set the initiator of the process instance to an authenticated user id provided in the camera header. To do this, you must first specify an initiator variable in the process definition:
<startEvent id="start" flowable:initiator="initiator" />
Then, if the user ID is included in a Camel header named CamelProcessInitiatorHeader, Camel routes can be defined as follows:
from("direct:startWithInitiatorHeader") .setHeader("CamelProcessInitiatorHeader", constant("kermit")) .to("flowable:InitiatorCamelCallProcess?processInitiatorHeaderName=CamelProcessInitiatorHeader");
The above article is from Pangu BPM Research Institute: http://vue.pangubpm.com/
Article translation submission: https://github.com/qiudaoke/flowable-userguide
For more articles, you can focus on WeChat official account: