Camel Events

This chapter describes how to work with events in Camel and Stardust. Camel components (file, csv, email, mina, etc.) are used to detect events such as file creation; email reception, record insert in a database, message reception from a socket. Once an event is detected, Camel plays the role of trigger to start a Stardust process. The Stardust model used in the examples below shows the data sent from Camel.

Stardust Model example

The TestData structure is defined as bellow :

TestData Structure

Events examples provided :

File Events

The camel-file component detects file creation on the local environment.

URI format

File endpoints can have the following URI format:

fileDirectoryName[?options]
Full description of the file component options could be found here.
The folder path is provided in the file component URI.

Example using the file component with Java DSL:

Camel is listening on the folder data/inbox/start, when a file is received in this folder, the file is consumed and Camel starts a new Stardust process using the camel-ipp component with the data provided in the input file (ProcessID and configuration). In this example, the Process_Id is TestProcess2 and the configuration is (data=TestData.id::7783834::long,TestData.name::Smith)

      from(file://data/inbox/start).convertBodyTo(String.class)
                  .process(new Processor()
                  {
                     public void process(Exchange exchange) throws Exception
                     {
                        String body = exchange.getIn().getBody(String.class);
                        Map<String, Object> headerMap = new HashMap<String, Object>();
                        if (body != null)
                        {
                           String[] stringTab = body.split(" ");
                           if (stringTab.length >= 2)
                           {
                              headerMap.put(CamelConstants.MessageProperty.PROCESS_ID, stringTab[0].trim());
                              headerMap.put("startProcessTest", stringTab[1].trim());
                           }
                        }
                        exchange.getIn().setHeaders(headerMap);
                     }
                  })
                  .to("ipp:authenticate:setCurrent?user=motu&password=motu")
                  .choice()
                  .when(header("startProcessTest").isEqualTo(1))
                  .to("ipp:process:start?data=TestData.id::7783834::long,TestData.name::Smith")
                  .when(header("startProcessTest").isEqualTo(2))
                  .to("ipp:process:start?processId=TestProcess1&data=${header.SimpleBoolean},${header.SimpleInteger}")
                  .when(header("startProcessTest").isEqualTo(3))
                  .to("ipp:process:start?processId=TestProcess2&dataMap=${header.testStartData}")
                  .end()
      ...

Mail Store Events

Camel provides a camel-mail component to detect emails into a mail box folder in a specific mail server.


URI format

Mail endpoints can have one of the following URI formats (for the protocols, SMTP, POP3, or IMAP, respectively):

smtp://[username@]host[:port][?options]
pop3://[username@]host[:port][?options]
imap://[username@]host[:port][?options]

More details about the email component could be find here.

The mail account and server configurations are provided in the component's endpoint URI.

This is an example using the mail component with Java DSL:

Camel is listening on the mail box folder. When an email is received for the specific account, it is consumed using pop3 protocol and Camel starts a new Stardust process using the camel-ipp component with the data provided in the processor and the email body. In this example, the Process_Id is TestProcess2 and Camel provides values for the data structure sent to Stardust (data=TestData.id::1112::long,TestData.name::${body})

      from(pop3://10.215.62.149?username=hedi2@igt.com&password=test&delete=true&consumer.delay=30000)
                  .process(new Processor()
                  {
                     public void process(Exchange exchange) throws Exception
                     {
                        Map<String, Object> headerMap = new HashMap<String, Object>();
                        headerMap.put(CamelConstants.MessageProperty.PROCESS_ID, "TestProcess2");
                        exchange.getIn().setHeaders(headerMap);
                     }
                  })
                  .to("ipp:authenticate:setCurrent?user=motu&password=motu")
                  .to("ipp:process:start?data=TestData.id::1112::long,TestData.name::${body}")
      ...

This is the configuration provided in the camel-mail URI :

Host 10.215.62.149
Port 110
Delay 30 seconds
Account hedi2@igt.com
Password test
Delete after consuming true

Database Events

Camel provides a camel-jpa component to detect SQL insertion into a database table.

URI format

jpa endpoints can have the following URI format:

jpa:[entityClassName][?options]

In the camel-jpa component URI you have to provide the full name of the Java Class annotated with JPA annotations. For example : jpa:com.infinity.integration.camel.event.database.PurchaseOrder


You have the following PurchaseOrder Entity Class.

@Entity
public class PurchaseOrder implements Serializable {
	private String name;
	private double amount;
	private String customer;
	public PurchaseOrder() {
	}
	public double getAmount() {
		return amount;
	}
	public void setAmount(double amount) {
		this.amount = amount;
	}
	//...
}

This is the Purchase Order table description:

Field Type
Name String
Amount Double
Customer String

The database configuration is done in persistence.xml file as follow :

 <persistence-unit name="camel" transaction-type="RESOURCE_LOCAL">
    <class>com.infinity.integration.camel.event.database.PurchaseOrder</class>
    <properties>
      <property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver" />
      <property name="openjpa.ConnectionURL" value="jdbc:postgresql://localhost:5432/OMS" />
      <property name="openjpa.ConnectionUserName" value="broker" />
      <property name="openjpa.ConnectionPassword" value="broker" />
      <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema" />
    </properties>

The JPA configuration is integrated in Spring configuration file as below :

<bean id="jpa" class="org.apache.camel.component.jpa.JpaComponent">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="camel" />
		<property name="jpaVendorAdapter" ref="jpaAdapter" />
	</bean>

	<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
		<property name="databasePlatform"
			value="org.apache.openjpa.jdbc.sql.PostgresDictionary" />
		<property name="database" value="POSTGRESQL" />
	</bean>

	<bean id="transactionTemplate"
		class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager">
			<bean class="org.springframework.orm.jpa.JpaTransactionManager">
				<property name="entityManagerFactory" ref="entityManagerFactory" />
			</bean>
		</property>
	</bean>

This is an example using the JPA component with Java DSL:

Camel is listening on the database table. When an insertion is done on the Purchase Order table, it is is received by Camel and it starts a new Stardust process using the camel-ipp component with the data provided in the processor and the Entity name field sent in the message body. In this example, the Process_Id is TestProcess2 and Camel provides values for the data structure sent to Stardust (data=TestData.id::1112::long,TestData.name::${body.name})

	from("jpa:com.infinity.integration.camel.event.database.PurchaseOrder")
                  .process(new Processor()
                  {
                     public void process(Exchange exchange) throws Exception
                     {
                        Map<String, Object> headerMap = new HashMap<String, Object>();
                        headerMap.put(CamelConstants.MessageProperty.PROCESS_ID, "TestProcess2");
                        exchange.getIn().setHeaders(headerMap);
                     }
                  })
                  .to("ipp:authenticate:setCurrent?user=motu&password=motu")
                  .to("ipp:process:start?data=TestData.id::1112::long,TestData.name::${body.name}")
                  .log(
                        "Test #${header.startProcessTest}: Created process instance OID: ${header.ippProcessInstanceOid} with name ${body.name}")
                  .to("mock:testStartProcessParameterData").to("ipp:authenticate:removeCurrent");

CSV Events

Camel provides the camel-csv Data Format using Apache Commons CSV framework in order to handle CSV payloads.

This is the Stardust model used in this project:

CSV Model

This is an example using the file component and CSV data format with Java DSL:

CSV Model

Camel is listening on the folder data, when a CSV file is received in this folder, the file is consumed and split line by line. Each valid line (not a comment) is unmarshaled using the csvFormat delimiter and then stored in a Map structure. Camel starts a new Stardust process through the camel-ipp component and provides this map as data to Stardust. In this example, the Process_Id is ShowContent and the data provided is the message body (data=Record::${body})

CsvDataFormat csvFormat = new CsvDataFormat();
      csvFormat.setDelimiter(",");
...
from("file://C:/data/?autoCreate=true&move=backup/${date:now:yyyyMMdd}/${file:onlyname}").split(
            body().tokenize("\n")).log("*** Before Transformer: ${body}").choice().when(
            body().not(body().startsWith("#"))).unmarshal(csvFormat)
            .process(new RecordTransformer("command", "subCommand", "args")).to(
                  "ipp:authenticate:setCurrent?user=motu&password=motu").to(
                  "ipp:process:start?processId=ShowContent&data=Record::${body}").end();

The following source code shows the creation of the Map structure:

List<String> content=(List<String>)exchange.getIn().getBody();
      logger.info(""+content);
      
      Map<String ,Object> params= new HashMap<String ,Object>(2);
      params.put(commandLabel, content.get(0));
      params.put(subCommandLabel, content.get(1));
      
      if(content.size()>2){
         List temp=new ArrayList();
         for(int i=2;i< content.size();i++){
           temp.add(content.get(i));
         }
         params.put(argsLabel,temp );
        
      }
     
      exchange.getIn().setBody(params);

CSV file example:

###################AUTO INTERFACE 3RD PARTY ACH###########################################################################################
AUTO,0,-1,CASH,THD PT ACH,CASH,THD PT ACH,,,,,,PROCESS,TEXT,T,TEXT,*.SUNGARD.P1.*ACH*.*REPT,-1,-1
AUTO,-1,DATE_MMDDYY,1,98
AUTO,1,POWIMAGE,RPT INFO TA,RPTNBR,10,s,n,,2,130
AUTO,2,POWIMAGE,RPT INFO TA,CONBR,3,s,n,,1,4
AUTO,-4,GROUP,RPT INFO TA,N
#############################END OF AUTO INTERFACE FILE###############################################################################

Timer Events

The Time Events are events based on the operating system time. Camel provides the camel-quartz component which provides a scheduled delivery of messages.

The quartz configuration is done in the component URI and based on quartz cron expression. For more details refer to the Quartz web site.

This is an example using the quartz component with Java DSL:

Camel receives a generated message each 20 seconds witch starts a new Stardust process through the camel-ipp component with the data provided in the processor. In this example, the Process_Id is TestProcess2 and camel provides value for the Stardust primitive data SimpleInteger (data=("SimpleInteger", 10)

	from(quartz://report?cron=0/20+*+*+*+*+?).process(new Processor()
            {
               public void process(Exchange exchange) throws Exception
               {
                  Map<String , Object> headerMap = new HashMap<String
	, Object>();
                  headerMap.put(CamelConstants.MessageProperty.PROCESS_ID, "TestProcess2");
                  headerMap.put("SimpleInteger", new Integer(10));
                  exchange.getIn().setHeaders(headerMap);

               }
            }).to("ipp:authenticate:setCurrent?user=motu&password=motu").to(
                  "ipp:process:start?processId=TestProcess1&data=${header.SimpleInteger}").log(
                  "Test #${header.startProcessTest}: Created process instance OID: ${header.ippProcessInstanceOid}")
                  .to(START_PROCESS_END).to("ipp:authenticate:removeCurrent");
    ...

Socket Events

The MINA is a networking framework that provides an asynchronous event-driven API and communicates over various protocols like TCP and UDP. The camel-mina component is used for network communications. It handles low level details, making it easy to communicate over network protocols such as TCP and UDP. The Mina component is located in the camel-mina module of the Camel distribution.

The URI looks like this:

mina:tcp://hostname[:port][?options]
mina:udp://hostname[:port][?options]
mina:vm://hostname[:port][?options]

In the following example, Camel is listening on localhost/port 8999. When a message is received, it is consumed using tcp protocol and Camel starts a new Stardust process using the camel-ipp component. In this example, the Process_Id is TestProcess1 and Camel provides values for the data structure sent to Stardust (data=TestData.id::1112::long,TestData.name::${body}).

       from("mina:tcp://localhost:8999?textline=true&sync=false")
            .log("message content:${body}")
            .to("ipp:authenticate:setCurrent?user=motu&password=motu")
            .to("ipp:process:start?processId=TestProcess1&data=TestData.id::1112::long,TestData.name::${body}")
            .log("Test #${header.startProcessTest}: Created process instance OID: ${header.ippProcessInstanceOid}")
            .to("ipp:authenticate:removeCurrent").to("mock:response");
      ...