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 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 Stardust 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.
The following commands are supported:
If you use routes with Spring DSL, please refer to section Configuring Routes with Spring DSL for details on the required configuration.
This command allows us to perform authentication to Stardust. Authentication is required to perform actions such us starting a process, completing an activity etc. 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 version 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 you use a model created with Stardust version older than 7.3.1, you
need 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 Stardust 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.
The process command supports the following sub-commands:
As core functionality the Camel Stardust 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, for example:
|
| 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.
For example:
|
Start sub-command usage example
The example below starts a process MyProcess 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 behavior 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<String,?>. See also 'Passing Data' usage samples. |
Continue Sub-command usage 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:

Figure: Process Definition

Figure: Activity Properties
The Order Transformation 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 figure 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. |
| state | Find all process instances with given states. For example, Active, Completed, Interrupted, Aborted and Halted. |
| dataFilters | Find all process instances with specified data.
For 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. |
Examples for sub-command find
Search based on processOid and completed states:
<to uri="ipp:process:find?processInstanceOid=101&state=completed"/>
Search for interrupted or aborted process instances by id:
<to uri="ipp:process:find?processId=TestProcess&state=interrupted, aborted"/>
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: $simple{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<String,Serializable> 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<String,?>. 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 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. |
For 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=$simple{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=$simple{body}"/>
<to uri="mock:endAttachmentRoute"/>
</route>
The Process Documents section displays the attachment file, as shown in the below screenshot:

Figure: Process Definition
The following example attaches the exchange body using the default value of the ippAttachmentFolderName option.
<to uri="ipp:process:attach?ippAttachmentFileName=testFile.txt&ippAttachmentFileContent=$simple{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. |
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=$simple{header.ippProcessInstanceOid}&processId=CustomSubProcess©Data=false&data=MessageBody::$simple{body}"/>
The following is a 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::$simple{body}"/>
<to uri="ipp:process:spawnSubprocess?parentProcessInstanceOid=$simple{header.ippProcessInstanceOid}&processId=CustomSubProcess©Data=false&data=MessageBody::$simple{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.
The following sub-commands are supported:
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. |
Example:
In the example below we search for hibernated activity by id:
<to uri="ipp:activity:find?processId=TestProces&activityId=$simple{header.ActivityID}&state=hibernated"/>
In the example below we search for activity instances using Ids defined in the message header:
<to uri="ipp:activity:find?processInstanceOid=$simple{header.processOid}&activityId=$simple{header.ActivityID}"/>
<to uri="ipp:activity:complete"/>
Complete command is used to complete an activity instance.
ipp:activity:complete
Example:
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
The data command supports the following sub-commands:
The following examples demonstrate the usage of to/fromXML sub-commands:
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
The opposite can be done by using the toXML sub-command. The command URI format:
<to uri="ipp:data:toXML"/>
The following examples demonstrate the usage of to/fromJSON sub-commands:
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"}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.
The following examples demonstrate the usage of to/fromCSV sub-commands:
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
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.
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 a 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. For further details, please refer to chapter
Client Side Properties of the
Developer Handbook.
A popular and recommended way to communicate with the Stardust runtime server is via the
SpringServiceFactory in which case you would find the following settings in the carnot.properties file:
Client.ServiceFactory = org.eclipse.stardust.engine.api.spring.SpringServiceFactory
If your Camel application acts as a remote client, make sure that the server as well as the client are configured for Spring Remoting as described in section Spring Remoting and Stardust of chapter Runtime Setup in the Spring Integration Guide.
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:
Approved::$simple{header.in.Approved} would have the same result!)
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 the steps to deploy the component on JBoss server.