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>org.eclipse.stardust.engine</groupId> <artifactId>camel-ipp</artifactId> <version>x.x.x</version> </dependency>
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 | |
| currentTx | Used to participate in an ongoing IPP transaction | |
| process | start | Start a process instance |
| continue | To complete an activity and set new out Data value | |
| find | To find process instances | |
| getProperties | To retrieve properties | |
| setProperties | To set properties | |
| attach | To add attachment | |
| spawnSubprocess | To spawn a subprocess | |
| activity | find | To find activity instances |
| complete | To complete an activity instance | |
| data | toXML | Convert Structured Data to XML format |
| fromXML | Convert from XML format to Structured Data | |
| toJSON | Convert Structured Data to JSON format | |
| fromJSON | Convert from JSON format to Structured Data | |
| toCSV | Convert Structured Data or Native Object to CSV format | |
| fromCSV | Convert from CSV format to Structured Data or Native Object | |
| toNativeObject | Convert Structured Data to NativeObject | |
| fromNativeObject | Convert from NativeObject to Structured Data | |
| toList | Convert Structured Data to List | |
| fromList | Convert from List to Structured Data |
Please refer to the individual endpoint documentation for a detailed list of available command, options, and examples.
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.
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 with a Camel Trigger.

Figure: Configuration Variables Parameters
Note: If user uses a model created with ipp version older than 7.3.1, he needs to remove the configuration variables of type String and keep new configuration variables of type Password.
The sub-command currentTx is used to participate in an ongoing IPP transaction.
ipp:authenticate:currentTx
The example below shows how we can use the current transaction instead of establishing a new session:
<from uri ="direct:consumertTestCurrentTx"/> <to uri="ipp:authenticate:currentTx"/> <to uri="ipp:activity:find?processId=testAuthenticateWithCurrentTx&activityId=AuthenticateWithCurrentTx&state=created"/> <to uri="ipp:activity:complete"/>
The process command allows us to perform process related actions such us starting a process, completing an activity, retrieve or set process properties.
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:
|
| synchronousMode | Whether or not to wait until the process instance creation is committed in Stardust. |
| data | populates process data after starting the process:
examples: |
| 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: |
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)}
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: |
| dataOutputMap | The data to be passed to each activity instance upon completion as java.util.Map |
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:

Figure: 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 command is capable of finding a number of process instances based on search criteria.
ipp:process:find
The process find command options are the following:
| 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. |
| activityId | The ID of the activity instance. |
| states | Find all process instances with given states. |
| dataFilters | Find all process instances with specified data.
example: |
| expectedResultSize | Indicate the number of process instances to find. -1 is used to get all instances.
UnexpectedResultException is thrown if the result size does not match the expected size. When the result size is 1, the exchange header "ippProcessInstances" will hold the process instance and the "ippProcessInstanceOid" header is populated with process instance OID. Otherwise the "ippProcessInstances" will hold the list of process instances matching the find criteria. |
Search based on processOid and completed states:
<to uri="ipp:process:find?processInstanceOid=101&state=completed"/>
Search for hibernated process by id:
<to uri="ipp:process:find?processid=TestProces&state=hibernated"/>
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.
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"/>
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
| 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 |
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 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. |
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.

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
The 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. |
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©Data=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©Data=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'.
The activity command allows us to perform activity related actions such us finding activities or completing an activity.
Find command is capable of finding a number of activity instances based on search criteria.
ipp:activity:find
The activity find command options are the following:
| 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. |
| activityId | The ID of the activity instance. |
| states | Find all activity instances with given states. |
| dataFilters | Find all activity instances with specified data.
example: |
| expectedResultSize | Indicate the number of activity instances to find. -1 is used to get all instances.
UnexpectedResultException is thrown if the result size does not match the expected size. When the result size is 1, the exchange header "ippActivityInstances" will hold the activity instance. Otherwise it will hold the list of activity instances matching the find criteria. |
In the example below we search for hibernated activity by id:
<to uri="ipp:activity:find?processid=TestProces&activityId=$simple{header.ActivityID}&state=hibernated"/>
Complete command is used to complete an activity instance.
ipp:activity:complete
In the example below we search for hibernated activity instance by id then we complete it:
<to uri="ipp:activity:find?processid=TestProces&activityId=$simple{header.ActivityID}&state=hibernated"/>
<to uri="ipp:activity:complete" />
The data command allows data type conversion between structured data and other data types such as XML, JSON or CSV.
The command URI format is as below:
ipp:data:sub-command
1- Converting from XML format to structured data:
In the following example the XML input will be converted to structured data using fromXML sub-command
<Person> <FirstName>Smith</FirstName> <LastName>Adam</LastName> <Address> <City>Great park</City> <State>London</State> </Address> </Person>
The command URI format:
<to uri="ipp:data:fromXML"/>
Below the structured data output:

Figure: Person Structured data
2- Converting from structured data to XML format:
The opposite can be done by using the toXML sub-command. The command URI format:
<to uri="ipp:data:toXML"/>
1- Converting from structured data to JSON data type:
In the following example the previous structured data will be converted to JSON data type using toJSON sub-command
<to uri="ipp:data:toJSON"/>
Below the JSON data type output:
Person {"Address":{"State":"London","City":"Great park"},"FirstName":"Smith","LastName":"Adam"}
2- Converting from JSON data type to structured data
The opposite can be done by using the fromJSON sub-command. The command URI format:
<to uri="ipp:data:fromJSON"/>
"XML" and "JSON" are standard and well-defined format. But this is not the case for "CSV". In practice, "CSV" refers to any text or file with the following features and limitations:
CSV therefore does not have the flexibility of XML or JSON format. For this reason, flat SDT will be handled properly by the CSV converter (to/from). In the current version, embeded SDT or fields having N cardinality within an SDT are not processed.
1- Converting from CSV format to structured data:
In the following example the CSV input will be converted to structured data using fromCSV sub-command
firstName,lastName,salary,DOB Peter,Adam,2000,03/11/1988
The first line in the CSV input contains the headers. It's required by the converter to know how to map the CSV columns to Structured data fields.
The command URI format:
<to uri="ipp:data:fromCSV?delimiter=,"/>
Below the structured data output:

Figure: Employee Structured data
2- Converting from structured data to CSV data type:
In the following example the previous structured data will be converted to CSV data type using toCSV sub-command
<to uri="ipp:data:toCSV?delimiter=|&autogenHeaders=true"/>
Below the CSV data type output:
firstName|lastName|salary|DOB Peter|Adam|2000|03/11/1988
The header line will not be generated if the autogenHeaders=false.
3- Converting from CSV format to structured data list:
In the following example the CSV input will be converted to structured data list using fromCSV sub-command
firstName,lastName,salary,DOB Peter,Smith,2500,05/25/1995 Kevin,Thomas,3000,06/25/1975
The command URI format:
<to uri="ipp:data:fromCSV?delimiter=,"/>
Below the structured data output:

Figure: Employees Structured data
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&password=motu" />
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"/>
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.
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).
In this chapter we'll show you a diffrent steps to deploy camel-ipp component on Jboss server.