Apache Camel

Apache Camel Timer Example

You can use Camel’s timer component to schedule tasks to occur either at a specified time or at regular intervals.

Timer comes as Camel’s core component. Its URI scheme is timer:

A timer component generates events which in turn triggers the endpoint that follows and generate messages. It uses uses the JRE’s built-in timer mechanism to generate message exchanges at regular intervals.

Before we start with our example, Let’s look into the setup details.

This example uses the following frameworks:

  1. Maven 3.2.3
  2. Apache Camel 2.15.1
  3. Spring 4.1.5.RELEASE
  4. Eclipse  as the IDE, version Luna 4.4.1.

1. Dependencies

I will be showing you some examples of camel components so you need to add the following dependencies:

  1. camel-core – basic module of apache camel.
  2. camel-stream – We will use this to send output to the console.
  3. camel-jms and activemq-camel – ActiveMQ JMS components.
  4. spring-context and camel-spring – Since we be configuring our camel context in spring.
  5. mysql-connector-java MySQL Driver.
  6. camel-jdbc to access the Camel JDBC component.
  7. spring-jdbc to configure JDBC resources in spring like DataSource
  8. slf4j-api and slf4j-log4j12 – This is for the log component. It relies on slf4j for the logger API and log4j as the logger implementation

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javacodegeeks.camel</groupId>
	<artifactId>camelHelloWorld</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-core</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-stream</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.1.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-spring</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.12</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.12</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.26</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-jdbc</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.1.5.RELEASE</version>
		</dependency>
	</dependencies>
</project>

2. Timer component’s URI format

The timer component’s URI format is:

timer:name[?options]

Where timer: is the URI scheme, name is the name of the Timer object, and one can configure the timer appending the query options to the URI. The name of the timer component helps us to reuse the timer across the endpoints so if you use the same name for all your timer endpoints, only one Timer object and thread will be used.

3. Message Exchange

The timer component doesn’t receive any message, it only generates messages so the inbound message of the generated exchange is null.
Thus the below statement returns null.

exchange.getIn().getBody();

4. Timer Example

Let’s start with a simple example that generates messages every second and sends it to console.
Our routing is:

from("timer://simpleTimer?period=1000")
.setBody(simple("Hello from timer at ${header.firedTime}"))
.to("stream:out");

We pass the timer URI to the from to generate an event every 1 sec. Next in the route is setBody which sets the outbound message. Header ${header.firedTime} contains the fired time. The message generated is then sent to console stream:out.

CamelTimerSimpleExample:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class CamelTimerSimpleExample {
	public static void main(String[] args) throws Exception {
		CamelContext camelContext = new DefaultCamelContext();
		try {
			camelContext.addRoutes(new RouteBuilder() {
				@Override
				public void configure() throws Exception {
					from("timer://simpleTimer?period=1000")
							.setBody(simple("Hello from timer at ${header.firedTime}"))
							.to("stream:out");
				}
			});
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
		}
	}
}

Output:

Hello from timer at Tue May 19 12:07:54 IST 2015
Hello from timer at Tue May 19 12:07:55 IST 2015
Hello from timer at Tue May 19 12:07:56 IST 2015

5. Timer Example using Spring

The above example we can be configured in spring context XML. For example,

applicationContext.xml:

>?xml version="1.0" encoding="UTF-8"?<

>beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       "<
	>camelContext xmlns="http://camel.apache.org/schema/spring"<
		>route<
			>from uri="timer://simpleTimer?period=1000" /<
			>setBody<
				>simple<Hello from timer at ${header.firedTime}>/simple<
			>/setBody<
			>to uri="stream:out" /<
		>/route<
	>/camelContext<

>/beans<

Note the <route> element. We set the uri in from element, attribute uri. Next we set the body using setBody element. The simple element within it contains the text that we want to set to the outbound message. Finally, to element contains the next endpoint in the router which is the console stream:out.

Let’s now run the context file.

CamelTimerSimpleExampleUsingSpring:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CamelTimerSimpleExampleUsingSpring {
	public static void main(String[] args) throws Exception {
		ApplicationContext appContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
		}
	}
}

Output:

Hello from timer at Tue May 19 12:18:50 IST 2015
Hello from timer at Tue May 19 12:18:51 IST 2015
Hello from timer at Tue May 19 12:18:52 IST 2015

6. Time and Pattern Options

We will first see the time and pattern options. Using time option, we can let the timer know when we want the first event to be fired. In t hepattern we specify the custom date pattern to use to set the time. The pattern expected is: yyyy-MM-dd HH:mm:ss or yyyy-MM-dd'T'HH:mm:ss.

CamelTimerTimePatternExample:

package com.javacodegeeks.camel;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class CamelTimerTimePatternExample {
	public static void main(String[] args) throws Exception {
		CamelContext camelContext = new DefaultCamelContext();
		try {
			camelContext.addRoutes(new RouteBuilder() {
				@Override
				public void configure() throws Exception {
					Date future = new Date(new Date().getTime() + 1000);

	                SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
	                String time = sdf.format(future);

	                fromF("timer://simpleTimer?time=%s&pattern=dd-MM-yyyy HH:mm:ss", time)
	                .setBody(simple("Hello from timer at ${header.firedTime}"))
	                .to("stream:out");
				}
			});
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
		}
	}
}

Output:

12:32| INFO | DefaultCamelContext.java 3164 | Route: route1 started and consuming from: Endpoint[timer://simpleTimer?pattern=dd-MM-yyyy+HH%3Amm%3Ass&time=19-05-2015+12%3A32%3A58]
12:32| INFO | DefaultCamelContext.java 2453 | Total 1 routes, of which 1 is started.
12:32| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.284 seconds
Hello from timer at Tue May 19 12:32:58 IST 2015
Hello from timer at Tue May 19 12:32:59 IST 2015
Hello from timer at Tue May 19 12:33:00 IST 2015

7. Delay and RepeatCount timer options

You can also delay the timer, make it to wait for the configured time before the first event is generated and one can also limit the maximum limit number of fires. We will club both the options in our example.
We will set the delay period to 2s and repeatCount to 2 which means the timer will wait for 2 seconds before it starts generating its first event and it will fire only for two times.

CamelTimerOtherOptionsExample:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class CamelTimerOtherOptionsExample {
	public static void main(String[] args) throws Exception {
		CamelContext camelContext = new DefaultCamelContext();
		try {
			camelContext.addRoutes(new RouteBuilder() {
				@Override
				public void configure() throws Exception {					
	                fromF("timer://simpleTimer?delay=2s&repeatCount=2")
	                .setBody(simple("Hello from timer at ${header.firedTime}"))
	                .to("stream:out");
				}
			});
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
		}
	}
}

Output:

Hello from timer at Tue May 19 12:46:20 IST 2015
Hello from timer at Tue May 19 12:46:21 IST 2015

8. Time Exchange Properties

When the timer is fired, the below information is added as properties to the Exchange.

  1. Exchange.TIMER_NAME The value of the name option.
  2. Exchange.TIMER_TIME The value of the time option.
  3. Exchange.TIMER_PERIOD The value of the period option.
  4. Exchange.TIMER_FIRED_TIME The time when the consumer fired.
  5. Exchange.TIMER_COUNTER The current fire counter. Starts from 1.

In this example, we will get these properties from the Exchange and set them to the body so that we can view them on console.
We will add a custom Processor

CamelTimerExchangePropertiesExample:

package com.javacodegeeks.camel;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class CamelTimerExchangePropertiesExample {
	public static void main(String[] args) throws Exception {
		CamelContext camelContext = new DefaultCamelContext();
		try {
			camelContext.addRoutes(new RouteBuilder() {
				@Override
				public void configure() throws Exception {
					Date future = new Date(new Date().getTime() + 1000);

					SimpleDateFormat sdf = new SimpleDateFormat(
							"dd-MM-yyyy HH:mm:ss");
					String time = sdf.format(future);

					fromF("timer://simpleTimer?time=%s&pattern=dd-MM-yyyy HH:mm:ss&period=1000", time)
					   .process(new Processor() {
						public void process(Exchange msg) {
							Date firedTime = msg.getProperty(
									Exchange.TIMER_FIRED_TIME,
									java.util.Date.class);
							int eventCount = msg.getProperty(
									Exchange.TIMER_COUNTER, Integer.class);
							String timerName = msg.getProperty(
									Exchange.TIMER_NAME, String.class);							
							int period = msg.getProperty(
									Exchange.TIMER_PERIOD, Integer.class);
							Date time = msg.getProperty(
									Exchange.TIMER_TIME, Date.class);
						
							
							msg.getOut().setBody("Exchange Properties: name: " + timerName + " time: " + time + " period: " + period + 
									" firedAt: " + firedTime + " counter: " + eventCount);
						}
					}).to("stream:out");
				}
			});
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
		}
	}
}

Output:

Exchange Properties: name: simpleTimer time: Tue May 19 14:13:54 IST 2015 period: 1000 firedAt: Tue May 19 14:13:54 IST 2015 counter: 1
Exchange Properties: name: simpleTimer time: Tue May 19 14:13:54 IST 2015 period: 1000 firedAt: Tue May 19 14:13:55 IST 2015 counter: 2
Exchange Properties: name: simpleTimer time: Tue May 19 14:13:54 IST 2015 period: 1000 firedAt: Tue May 19 14:13:56 IST 2015 counter: 3
Exchange Properties: name: simpleTimer time: Tue May 19 14:13:54 IST 2015 period: 1000 firedAt: Tue May 19 14:13:57 IST 2015 counter: 4

9. Poll Database Table Using Timer

Database schema contains customer table.

db-schema.sql:

drop table if exists `customer`;
CREATE TABLE `customer` (
  `ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR(100) NOT NULL,
  `STATUS` VARCHAR(50) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

We also need some sample data.

db-test.sql:

insert into customer(id, name, status) values (1, "Joe", "NEW");
insert into customer(id, name, status) values (2, "Sam", "NEW");
insert into customer(id, name, status) values (3, "Rahul", "NEW");

Let’s configure DataSource in spring context XML. We also initialize the database using the above scripts.

dataSourceApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
       ">
	<jdbc:initialize-database data-source="dataSource"
		enabled="true">
		<jdbc:script location="classpath:db-schema.sql" />
		<jdbc:script location="classpath:db-test-data.sql" />
	</jdbc:initialize-database>
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost/test" />
		<property name="username" value="root" />
		<property name="password" value="mnrpass" />
	</bean>
</beans>

We poll the customer table every 1 second and then split the retrieved rows so that the processor can process one row at a time. The processor in our example is very simple but in general it can be something that deals with the new customer and then you can even update the customer status that it is no more new so that next time the timer polls you won’t see the processed record.

CamelJdbcPollingExample:

package com.javacodegeeks.camel;

import java.util.Map;

import javax.sql.DataSource;

import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.jndi.JndiContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CamelJdbcPollingExample {
	public static void main(String[] args) throws Exception {
		ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("dataSourceApplicationContext.xml");
		DataSource dataSource = (DataSource) context.getBean("dataSource");
		JndiContext jndiContext = new JndiContext();
		jndiContext.bind("dataSource", dataSource);
		CamelContext camelContext = new DefaultCamelContext(jndiContext);
		try {
			camelContext.addRoutes(new RouteBuilder() {
				@Override
				public void configure() throws Exception {
					from("timer://pollTable?period=1s")
                    .setBody(constant("select * from customer where status = 'NEW'"))
                    .to("jdbc:dataSource")
                    .split(simple("${body}"))
                    .process(new Processor() {
						
						public void process(Exchange exchange) throws Exception {
							Map customer = exchange.getIn().getBody(Map.class);
							System.out.println("Process customer " + customer);
						}
					});
				}
			});
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
			context.close();
		}
	}
}

Output:

Process customer {ID=1, NAME=Joe, STATUS=NEW}
Process customer {ID=2, NAME=Sam, STATUS=NEW}
Process customer {ID=3, NAME=Rahul, STATUS=NEW}
Process customer {ID=1, NAME=Joe, STATUS=NEW}
Process customer {ID=2, NAME=Sam, STATUS=NEW}
Process customer {ID=3, NAME=Rahul, STATUS=NEW}

10. Download the Eclipse Project

This was an example about Apache Camel Timer.

Download
You can download the full source code of this example here: camelTimerExample.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Shiva
Shiva
6 years ago

When I change the system time say 1 hour forward, it stops the route. Is there a reason for it? Should I use a different component like Scheduler for it?

Back to top button