Camel Stardust Component

The Camel Stardust component allows you to address a Stardust runtime system using special URIs as part of a Camel route.
The Stardust component has several endpoints which have different options. They allow to communicate with a Stardust runtime environment and to interact with the object instances of the BPM environment, i.e. process instances, activity instances, documents, etc.

Maven users will need to add the following dependency to their pom.xml for this component:

<dependency>
	<groupId>com.infinity.bpm</groupId>
		<artifactId>camel-ipp</artifactId>
	    <version>x.x.x</version>
</dependency>

URI Format

The URI scheme for a Stardust component is as follows

ipp:command:subcommand[?options]

Query options can be appended as below to the URI:?option=value&option=value&...

The table below summarizes the list of the commands supported by the component

Command Sub Command Description
authenticate setCurrent Used to establish a new session
removeCurrent To disconnect the user
process Start Start a process instance
continue To complete an activity and set new out Data value
find To find a process instance
getProperties To retrieve properties
setProperties To set properties
attach To add attachment

Please refer to the individual endpoint documentation for a detailed list of available command, options, and examples.

Supported Commands

Authenticate Command

This command allows us to perform authentication to Stardust. Authentication is required to perform actions such us starting a process, completing an activity... The command URI format is as below:

ipp:authenticate:setCurrent?user=<userAccount>&password=<password>
Option Description
User The ID of the user. If not explicitly specified as an option in the URI, the message header is examined for the key ippUser.
Password The password of the user. If not explicitly specified as an option in the URI, the message header is examined for the key ippPassword.
partition The tenant partition of the user. If not explicitly specified as an option in the URI, the message header is examined for the key ippPartition. The default partition is used when left empty.
realm The user realm. If not explicitly specified as an option in the URI, the message header is examined for the key ippRealm. The default realm is used when left empty.
domain The user domain. If not explicitly specified as an option in the URI, the message header is examined for the key ippDomain. The default domain is used when left empty.

If you're relying on a technical user in your Camel route, consider pre-defining these user credentials via the org.eclipse.stardust.ui.client.util.client.ClientEnvironment. This way you can avoid having to specify the password directly in the route and as only the user's ID is needed.

Example:

The example below is used to authenticate user motu.

ipp:authenticate:setCurrent?user=motu&password=motu

Acquiring a Stardust user session from information in the message header.

ipp:authenticate:setCurrent?$user=simple{header.user}&password=$simple{header.pwd}&partition=$simple{header.partition}

The sub-command removeCurrent is used to disconnect users.

ipp:authenticate:removeCurrent

Note: From IPP 7.1.1, the authentication endpoint have been generated using the configuration variables parameters provided for the username and password. So the endpoint needs to be provided only if the process is being started without a Camel Trigger.

Configuration Variables Parameters

Figure: Configuration Variables Parameters

Process Command

The process command allows us to perform process related actions such us starting a process, completing an activity, retrieve or set process properties.

Start Sub-Command

As core functionality the camel-ipp component allows us to start a process instance from a Camel route and optionally populate data within the process.

	ipp:process:start?processId=<processId>

When using the ExchangePattern OutOnly, no message properties are preserved and the header ippProcessInstanceOid is the only piece of information returned in the Out Message. For all other exchange patterns all parts of the original message are preserved and the ippProcessInstanceOid is set in the header of the In Message.

Name Description
processId The processId value is mandatory to start a process. There are two ways to populate it:
  • Use processId option
  • Populate ippProcessId header property.
  • synchronousMode Whether or not to wait until the process instance creation is committed in Stardust.
    data populates process data after starting the process:
    examples:
  • data=::${body}
  • data=TestData.id::11111::long,TestData.name::XXX
  • dataMap To populate many data at the same time after starting the process. Please note that you cannot set data and dataMap at the same time.
    examples:
  • dataMap=${header.testStartData}
  • Example:

    The example below starts "processId" process and populates "dataId" with the content of the message.

    ipp:process:start?processId=MyProcess&data=MessagePayload::$simple{bodyAs(java.lang.String)}
    

    Continue Sub-Command

    Instructs a process instance to continue by completing all currently 'waiting' (suspended or hibernated) activities.

    ipp:process:continue
    
    Name Description
    processInstanceOid Contains the processInstanceOid to be used. This option is not mandatory. As a replacement, you can set the processed in ippProcessInstanceOid header property. As a default behaviour the header property is automatically populated by the component
    dataOutput Populates the activity out data. Please note that you have to take the IDs of the data mappings itself, not the ID of the data in the process model.
    examples:
  • dataOutput=::${body}
  • dataOutput=TestData.id::9999::long,TestData.name::NewName
  • dataOutputMap The data to be passed to each activity instance upon completion as java.util.Map. See also 'Passing Data' usage samples.
    Example:

    Continuing a waiting process instance using an OID from the message header

    <to uri="ipp:process:continue?processInstanceOid=$simple{header.MyOid)}"/>
    

    Use the processInstanceOid option to specify for which process instance the operation should be carried out.

    Continuing a waiting process instance using the default message header field

    <route>
    	<from uri="jms:queue:IncomingQueue"/>
    	<to uri="ipp:process:start?processId=OrderProcessing"/>
    	<to uri="bean:orderTransformation?method=transformMessageBody"/>
    	<to uri="ipp:process:continue?dataOutput=Order::$simple{body}"/>
    </route>
    

    The above route consumes incoming JMS messages with a payload that is not in the correct format for the business data representation in the Stardust. But instead of first doing a transformation and then starting a process, a 'blank' process instance is created as a first thing after receiving a message to serve as a representation of the ongoing transformation in Camel. And after the transformation has completed successfully, we let the process continue. This is a nice example for multiple interactions between the Camel route and Stardust in the context of an entity, a process instance in this case.

    You don't need to specify for which process instance to execute the 'continue' command if a previous 'start' command has set the message header ippProcessInstanceOid to the OID of the created instance, therefore setting the context for any subsequent commands that operate on a process instance!

    The corresponding process model in Stardust could look something like this:

    Activity Properties

    Figure: Process Definition

    Process Definition

    Figure: Activity Properties

    The "Order Processing" BPM process defines a first activity called "Wait for Order Transformation" which has been configured as a blocking activity via the "Hibernate Initially" checkbox (see Fig. 2: Activity Properties). The process waits until the activity is completed via the 'continue' command from the Camel route which also passes the transformed 'Order' payload as data output of the activity.

    Find Sub-Command

    Find command is capable of finding a number of process instances based on search criteria.

    ipp:process:find
    

    The result of the find is in the header under the key "ippProcessInstances".

    Name Description
    processInstanceOid The OID of the process instance. If not specified explicitly as an option in the URI, the message header is examined for a field with the key ippProcessInstanceOid.
    processId The ID of the process instance.
    states Find all process instances with given states.
    dataFilters Find all process instances with specified data.
    example:
  • dataFilters=Person.name=Harshad,AccountNumber::363366::long
  • Example:

    Search based on processOid and completed states:

    <to uri="ipp:process:find?processInstanceOid=101&state=completed"/> 
    

    In the example below we search for hibernated process by id:

    <to uri="ipp:process:find?processid=TestProces&state=hibernated"/> 
    

    Find result splitter

    It's possible to iterate over activity or process instances resulting from the "find" command using a splitter. The class org.eclipse.stardust.engine.extensions.camel.splitter.InstancesSplitter implements the Splitter EIP in a Camel route for messages that contain process/activity instances. The OID of the activity or process will be populated in the header of the new split message.

    The fields of this class allow to control other runtime behavior, e.g. to retain the body of the original message or any or all of the original headers.

    Field Description Type Default Mandatory
    retainBody whether or not to retain the original body of the message (the Process/Activity Instance). The body is preserved by default. boolean true No
    retainHeaders whether or not to retain the original headers of the message. boolean false No
    retainHeadersList indicate the headers of the original message resulting from the find command to retains. List<String> null No

    There are two splitter methods splitProcessInstances and splitActivityInstances that determine on which entities the split would be performed.

    Example:

    The example below shows how to split process instances related to "TradeEventProcessing" processId resulting from a "find" command.

    <to uri="ipp:process:find?processId=TradeEventProcessing"/>
    <split>
    	<method bean="standardSplitter" method="splitProcessInstances"/>
    	<log message="Process instance OID: ${header.ippProcessInstanceOid}"/> 
    </split>
    <bean id="standardSplitter" class="org.eclipse.stardust.engine.extensions.camel.splitter.InstancesSplitter"/>
    

    get/setProperties Sub-Command

    Retrieves (getProperties) or manipulates (setProperties) the properties (also called Data-Paths) of a process instance.
    When retrieving properties, the result will be placed in the message header with the key ippProcessInstanceProperties as a java.util.Map object.

    Name Description
    processInstanceOid The OID of the process instance. If not specified explicitly as an option in the URI, the message header is examined for a field with the key ippProcessInstanceOid.
    properties The data to be set as properties (See also 'Passing Data' usage samples) or a comma-separated list of IDs in case of retrieving properties.
    propertiesMap The data to be set as properties as java.util.Map. See also 'Passing Data' usage samples.
    Example:

    Setting process properties with data from a bean invocation.

    <to uri="ipp:process:setProperties?processInstanceOid=3843&properties=Category::$simple{bean:categoryService.getCategory}"/>
    

    Setting process properties using the default Header ippProcessInstanceProperties.

    <to uri="bean:dataLookup?method=setProcessProperties"/>
    <to uri="ipp:process:setProperties?processInstanceOid=76"/>
    

    Retrieving selected process properties.

    <to uri="ipp:process:getProperties?processInstanceOid=7843&properties=ClientId,OrderTotal"/>
    <log message="The value of the process property ClientId is: $simple{header.ippProcessInstanceProperties[ClientId]}"/>
    

    Retrieving all process properties.

    <route>
    	<from uri="jms:queue:clientOrderQueue"/
    	<to uri="ipp:process:start?processId=StraightThroughProcessing"/>
    	<to uri="ipp:process:getProperties"/>
    	<choice>
    		<when>
    	    	<simple>header.ippProcessInstanceProperties[Result] != null</simple>
    	        <log message="Success! Result: $simple{header.ippProcessInstanceProperties[Result]}"/>
    	    </when>
    	    <otherwise>
    	   		<log message="The Stardust Process completed with errors."/>
    	    </otherwise>
    	<choice/>
    </route>
    

    This route example shows how a Camel route can be used in conjunction with Stardust to operate on or return the result of a process invocation. It is assumed that the Stardust process definition "StraightThroughProcessing" is designed to be executed in one single transaction. Therefore, invoking the URI "ipp:process:start" in synchronous mode (the default) returns only after the process instance in Stardust has been commited. And this happens at the end of the complete process or if the process instance has been interrupted due to exceptions. Subsequently it is then safe to retrieve the properties of the process instance (notice the implicit use of the ippProcessInstanceOid header) for further processing. Any properties that the process definition exposes could be returned to the caller, for example if the route originated from a web service or JMS queue using the InOut Exchange Pattern.

    Note: For simplicity we've left out the possibility that a rollback of the process instance creation could occur in the case of RuntimeExceptions.

    Attach Sub-Command

    Attach document to the process by specifying the content, the file name and the folder name where the document will be created in the repository.

    Name Description
    ippAttachmentFileName The attachment file name in the process. It will be created in the document repository.
    ippAttachmentFolderName The folder name where the attachment file will be created. If not specified explicitly as an option in the URI, the resulting document is stored under /process-instances/year/month/day/xxx/pi-oid/.
    ippAttachmentFileContent The attachment file content.
    Example:

    Attach the exchange body content to the process using a file named testFile.txt located in the repository under the temp folder .

    <to uri="ipp:process:attach?ippAttachmentFileName=testFile.txt&ippAttachmentFolderName=temp&ippAttachmentFileContent=${body}"/>
    

    This is an attachment route example:

    <route>
    	<from uri="direct:attachmentRoute"/>
            <to uri="ipp:authenticate:setCurrent?user=motu&password=motu"/>	
        	<to uri="ipp:process:start?processId=StartProcessAndAttachFile"/>	
        	<to uri="ipp:process:continue"/>	
        	<to uri="ipp:process:attach?ippAttachmentFileName=testFile.txt&ippAttachmentFolderName=temp&ippAttachmentFileContent=${body}"/>
        	<to uri="mock:endAttachmentRoute"/>
    </route>
    

    The Process Documents section displays the attachment file.

    Attached file

    Figure: Process Definition

    The following example attach the exchange body using the default value of ippAttachmentFolderName option.

    <to uri="ipp:process:attach?ippAttachmentFileName=testFile.txt&ippAttachmentFileContent=${body}"/>
    

    The Document Repository section displays the Default Path.

    Figure: Default Path

    spawnSubprocess Sub-Command

    spawnSubprocess command is capable of spawning new processes.

    Name Description
    parentProcessInstanceOid The parent process instance Oid is mandatory. if not set explicitly in the route, the ippProcessInstanceOid in the header should be used and interpreted as the current context and used as the parentOid automatically
    processId The ID of the process instance.It is mandatory.
    copyData copyData is a boolean flag, it is optional. By default, it is set to true.
    data data is optional, if copyData is true, setting of data is not allowed.
    Example:

    Spawn a subprocess named CustomSubProcess from a parent process instance which have been set from a previous startprocess command.

    <to uri="ipp:process:spawnSubprocess?parentProcessInstanceOid=${header.ippProcessInstanceOid}&processId=CustomSubProcess&copyData=false&data=MessageBody::${body}"/>
    

    This is an spawn route example:

    
    <route>
       <from uri="direct:startSpawnSubProcessEndpointRoute"/>
       <to uri="ipp:authenticate:setCurrent?user=motu&password=motu"/>	
       <to uri="ipp:process:start?processId=MainProcess&modelId=SpawnSubProcessModel&synchronousMode=false&data=MessageBody::${body}"/>	
       <to uri="ipp:process:spawnSubprocess?parentProcessInstanceOid=${header.ippProcessInstanceOid}&processId=CustomSubProcess&copyData=false&data=MessageBody::${body}"/>
       <to uri="ipp:authenticate:removeCurrent"/>
    </route>
    
    

    This route example shows how a Camel route can be used in conjunction with Stardust to spawn a subprocess. After authentication, the process definition "MainProcess" is designed to be executed in asynchronous mode. Then another "CustomSubProcess" process is executed and spawned from the parent process instance which have been saved in the header 'ippProcessInstanceOid'.

    Spring DSL Syntax

    In order to avoid the SAXParseException when configuring routes with Spring DSL, you have to replace all special characters by its HTML code equivalent.
    eg:

    <to uri="ipp:authenticate:setCurrent?user=motu&password=motu" />

    This command you have to replace it by:

    <to uri="ipp:authenticate:setCurrent?user=motu&amp;password=motu" />

    Setting up the Stardust component

    The Stardust Component behaves like a regular client application to the Stardust server using Stardust's Java API. Internally it relies on the ClientEnvironmentclass from the ipp-utils library to establish a communication channel with a Stardust runtime environment.

    By default this class uses the Carnot.ClientServiceFactorysetting, so all you basically need is to have a carnot.properties file in the classpath of your Camel application which is configured with the necessary settings for a Stardust client. See also this chapter in the Stardust documentation for further details:

    Stardust Documentation > Developer Handbooks > Operation Guide > Stardust Properties > Client Side Properties

    A popular and recommended way to communicate with the Stardust runtime server is via the SpringServiceFactory in which case you'd find the following settings in the carnot.properties file:

    Client.ServiceFactory = org.eclipse.stardust.engine.api.spring.SpringServiceFactory
    

    If you're Camel application acts as a remote client, make sure that the server as well as the client are configured for Spring Remoting as described here:

    Stardust Documentation > Developer Handbooks > Spring Integration Guide > Runtime Setup > Spring Remoting and Stardust

    The most straight-forward way, however, is to deploy Camel and the Stardust runtime engine inside the same web application sharing the same Spring application context. This way the communication between Camel and Stardust's services happens via local calls. This has one great advantage over using Spring Remoting: The possibility to use transaction propagation. In this case, simply add the following bean declaration to your Spring context to take full advantage of this type of deployment, e.g. by being able to pre-define technical users or control the use of the built-in ServiceFactoryCache via the bean's properties.

    <bean id="ippClientEnvironment" class="org.eclipse.stardust.ui.client.util.client.spring.SpringClientEnvironment"/>
    

    Passing data to the Stardust endpoints

    The Stardust's API in many cases expects data to be passed as a java.util.Map<String, String> object with the String keys representing IDs of process model elements. The most common use cases are:

    For these operations the Camel Stardust component provides the possibility to dynamically create the data map from a list of parameters or, for more complicated scenarios, you may create the map yourself, place it in the Exchange message, and refer to it in the endpoint URI. The basic difference between the two approaches to pass data to a Stardust endpoint can easily be seen in the presence of options which are mutually exclusive.

    For example: data vs. dataMap, properties vs. propertiesMap; dataOutput vs. dataOutputMap, etc.

    Example:

    The following examples demonstrate some of these usage scenarios ...

    Creating structured data (SDT) and primitive data objects with fixed values.

    <to uri="ipp:process:start?data=Person.name::Smith,Person.id::746633::long,Approved::true::boolean"/>
    

    The comma-separated data list contains three items which follow the pattern

    name::value[::type]
    

    Two of these items represent inner fields of a structured data object (identified by the dot '.' in the name). As a result of this endpoint invocation, a java.util.Map<String,?> object is constructed which contains two items: Another Map object representing the Person SDT and a Boolean. This data map would look like this in a JSON representation:

    {
    	"Approved": true,
    	"Person": {
    	          	"id": 746633,
    				"name": "Smith"
    	}
    } 
    

    This simple conversion mechanism currently supports the following types represented by their keywords:

    As mentioned however, this conversion mechanism only supports fixed values that are know at the time the endpoint URI is constructed. Also, the creation of structured data types is limited to only one level of inner maps; specifying "Person.Address.Street" would not work.

    In order to dynamically find and create data parameters in a more powerful way, the Stardust Component supports Camel's Simple Language.

    Passing data objects using message values and Simple Language expressions

    <to uri="ipp:process:start?data=Person::$simple{header.PersonMap},$simple{header.Approved},XMLPayload::$simple{body}"/>
    

    This example shows how easy it is to reference data that is contained in the exchanged Camel message by using Simple Language expressions. The above endpoint invocation yields a similar result as in the first example, but let's look at the differences more closely:

    Passing data objects using message values with Simple Language type conversions and expressions

    <to uri="ipp:process:setProperties?data=Approved::$simple{headerAs(Approved, java.lang.Boolean)},Price::$simple{bodyAs(java.lang.Float)}"/>
    

    In this example we're setting two properties of a process instance (in the Stardust Process Model these are called OUT-data-paths) with the names "Approved" and "Price". The "Approved" value is found in the message header and the price is the message body. Both values are not of the expected type as defined in the Stardust Process definition (the message might contain simple Strings) and therefore conversion expressions of Camel's Simple Language are applied.

    Passing data as a complete Map object

    <to uri="ipp:activity:complete?dataOutputMap=$simple{header.CompleteActivityDataMap}"/>
    

    This example shows that for very complex scenarios there's always the option of assembling the data map which is needed for the Stardust endpoint invocation in a previous step of the Camel route and then referring to it as a whole using the corresponding ...Map option (dataOutputMap in this case).

    Setup Camel-IPP Component on Jboss server

    In this chapter we'll show you a diffrent steps to deploy camel-ipp component on Jboss server.