Cache Component
Warning |
---|
This component is deprecated. As of Camel 2.18.0 You should use Ehcache. |
Available as of Camel 2.1
The cache component enables you to perform caching operations using EHCache as the Cache Implementation. The cache itself is created on demand or if a cache of that name already exists then it is simply utilized with its original settings.
The Cache component has the following abilities
a> In Producer mode, the component provides the ability to direct payloads in exchanges to a stored in a pre-existing or created-on-demand Cache. The producer mode supports operations to ADD/UPDATE/DELETE/DELETEALL elements in a cache. (Examples given below)
b> In Consumer mode, the component provides the ability to listen on a pre-existing or created-on-demand Cache using an event Listener and receive automatic notifications when any cache activity take place (i.e ADD/UPDATE/DELETE/DELETEALL). Upon such an activity taking place, an exchange containing header elements describing the operation and cachekey and a body containing the just added/updated payload is placed and sent. In case of a DELETEALL operation the body of the exchanage is not populated.
c> There are a set of nice processors to the camel-cache component to provide the ability to perform cache lookups and selectively replace payload content at the
- body
- token
- xpath level
...
This component supports producer and event based consumer endpoints.
The Cache consumer is an event based consumer and can be used to listen and respond to specific cache activities. If you need to perform selections from a pre-existing cache,
...
use the processors defined for the cache component.
Maven users will need to add the following dependency to their pom.xml
for this component:
Code Block | ||||
---|---|---|---|---|
| ||||
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-cache</artifactId> <version>x.x.x</version> <!-- use the same version as your Camel core version --> </dependency> |
URI format
Code Block |
---|
cache://cacheName[?options] |
...
You can append query options to the URI in the following format, ?option=value&option=value#beanRef&...
Options
Name | Default Value | Description |
---|---|---|
|
| The numer number of elements that may be stored in the defined cache |
|
| The number of elements that may be stored in the defined cache. Options include
|
|
| Specifies whether cache may overflow to disk |
|
| Sets whether elements are eternal. If eternal, timeouts are ignored and the |
|
| The maximum time between creation time and when an element expires. |
|
| The maximum amount of time between accesses before an element expires |
| | Whether the disk store persists between restarts of the Virtual Machine. |
|
| The number of seconds between runs of the disk expiry thread. The default value |
Result
The result is returned in the OUT body as an ArrayList<HashMap<String, Object>>
. The List
object contains the list of rows and the Map
objects contain each row with the String
key as the column name.
Note: This component fetches ResultSetMetaData
to be able to return the column name as the key in the Map
.
Message Headers
Header | Description |
---|---|
| If the query is a |
| If the query is an |
Samples
In the following example, we fetch the rows from the customer table.
First we register our datasource in the Camel registry as testdb
:
Wiki Markup |
---|
{snippet:id=register|lang=java|url=camel/trunk/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcRouteTest.java} |
Then we configure a route that routes to the JDBC component, so the SQL will be executed. Note how we refer to the testdb
datasource that was bound in the previous step:
Wiki Markup |
---|
{snippet:id=route|lang=java|url=camel/trunk/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcRouteTest.java} |
Or you can create a DataSource
in Spring like this:
Wiki Markup |
---|
{snippet:id=example|lang=java|url=camel/trunk/components/camel-jdbc/src/test/resources/org/apache/camel/component/jdbc/camelContext.xml} |
We create an endpoint, add the SQL query to the body of the IN message, and then send the exchange. The result of the query is returned in the OUT body:
Wiki Markup |
---|
{snippet:id=invoke|lang=java|url=camel/trunk/components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcRouteTest.java} |
Sample - Polling the database every minute
If we want to poll a database using the JDBC component, we need to combine it with a polling scheduler such as the Timer or Quartz etc. In the following example, we retrieve data from the database every 60 seconds:
...
from("timer://foo?period=60000").setBody(constant("select * from customer")).to("jdbc:testdb").to("activemq:queue:customers");
. | ||
|
| Camel 2.8: If you want to use a custom factory which instantiates and creates the EHCache |
|
| Camel 2.8: Sets a list of EHCache |
|
| Camel 2.8: Sets a list of |
|
| Camel 2.10: To configure using a cache key by default. If a key is provided in the message header, then the key from the header takes precedence. |
|
| Camel 2.10: To configure using an cache operation by default. If an operation in the message header, then the operation from the header takes precedence. |
objectCache | false | Camel 2.15: Whether to turn on allowing to store non serializable objects in the cache. If this option is enabled then overflow to disk cannot be enabled as well. |
Cache Component options
Name | Default Value | Description |
---|---|---|
|
| To use a custom |
|
| To use a custom |
|
| Camel 2.13/2.12.3: To configure the location of the |
Sending/Receiving Messages to/from the cache
Message Headers up to Camel 2.7
Div | ||||||
---|---|---|---|---|---|---|
| ||||||
|
Message Headers Camel 2.8+
Info | ||
---|---|---|
| ||
The header names and supported values have changed to be prefixed with 'CamelCache' and use mixed case. This makes them easier to identify and keep separate from other headers. The CacheConstants variable names remain unchanged, just their values have been changed. Also, these headers are now removed from the exchange after the cache operation is performed. |
Div | ||||||
---|---|---|---|---|---|---|
| ||||||
|
The CamelCacheAdd
and CamelCacheUpdate
operations support additional headers:
Div | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||
|
Cache Producer
Sending data to the cache involves the ability to direct payloads in exchanges to be stored in a pre-existing or created-on-demand cache. The mechanics of doing this involve
- setting the Message Exchange Headers shown above.
- ensuring that the Message Exchange Body contains the message directed to the cache
Cache Consumer
Receiving data from the cache involves the ability of the CacheConsumer to listen on a pre-existing or created-on-demand Cache using an event Listener and receive automatic notifications when any cache activity take place (i.e CamelCacheGet/CamelCacheUpdate/CamelCacheDelete/CamelCacheDeleteAll). Upon such an activity taking place
- an exchange containing Message Exchange Headers and a Message Exchange Body containing the just added/updated payload is placed and sent.
- in case of a CamelCacheDeleteAll operation, the Message Exchange Header CamelCacheKey and the Message Exchange Body are not populated.
Cache Processors
There are a set of nice processors with the ability to perform cache lookups and selectively replace payload content at the
- body
- token
- xpath level
Cache Usage Samples
Example 1: Configuring the cache
Code Block |
---|
from("cache://MyApplicationCache" +
"?maxElementsInMemory=1000" +
"&memoryStoreEvictionPolicy=" +
"MemoryStoreEvictionPolicy.LFU" +
"&overflowToDisk=true" +
"&eternal=true" +
"&timeToLiveSeconds=300" +
"&timeToIdleSeconds=true" +
"&diskPersistent=true" +
"&diskExpiryThreadIntervalSeconds=300")
|
Example 2: Adding keys to the cache
Code Block |
---|
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("direct:start")
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_OPERATION_ADD))
.setHeader(CacheConstants.CACHE_KEY, constant("Ralph_Waldo_Emerson"))
.to("cache://TestCache1")
}
};
|
Example 2: Updating existing keys in a cache
Code Block |
---|
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("direct:start")
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_OPERATION_UPDATE))
.setHeader(CacheConstants.CACHE_KEY, constant("Ralph_Waldo_Emerson"))
.to("cache://TestCache1")
}
};
|
Example 3: Deleting existing keys in a cache
Code Block |
---|
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("direct:start")
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_DELETE))
.setHeader(CacheConstants.CACHE_KEY", constant("Ralph_Waldo_Emerson"))
.to("cache://TestCache1")
}
};
|
Example 4: Deleting all existing keys in a cache
Code Block |
---|
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("direct:start")
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_DELETEALL))
.to("cache://TestCache1");
}
};
|
Example 5: Notifying any changes registering in a Cache to Processors and other Producers
Code Block |
---|
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("cache://TestCache1")
.process(new Processor() {
public void process(Exchange exchange)
throws Exception {
String operation = (String) exchange.getIn().getHeader(CacheConstants.CACHE_OPERATION);
String key = (String) exchange.getIn().getHeader(CacheConstants.CACHE_KEY);
Object body = exchange.getIn().getBody();
// Do something
}
})
}
};
|
Example 6: Using Processors to selectively replace payload with cache values
Code Block |
---|
RouteBuilder builder = new RouteBuilder() {
public void configure() {
//Message Body Replacer
from("cache://TestCache1")
.filter(header(CacheConstants.CACHE_KEY).isEqualTo("greeting"))
.process(new CacheBasedMessageBodyReplacer("cache://TestCache1","farewell"))
.to("direct:next");
//Message Token replacer
from("cache://TestCache1")
.filter(header(CacheConstants.CACHE_KEY).isEqualTo("quote"))
.process(new CacheBasedTokenReplacer("cache://TestCache1","novel","#novel#"))
.process(new CacheBasedTokenReplacer("cache://TestCache1","author","#author#"))
.process(new CacheBasedTokenReplacer("cache://TestCache1","number","#number#"))
.to("direct:next");
//Message XPath replacer
from("cache://TestCache1").
.filter(header(CacheConstants.CACHE_KEY).isEqualTo("XML_FRAGMENT"))
.process(new CacheBasedXPathReplacer("cache://TestCache1","book1","/books/book1"))
.process (new CacheBasedXPathReplacer("cache://TestCache1","book2","/books/book2"))
.to("direct:next");
}
};
|
Example 7: Getting an entry from the Cache
Code Block |
---|
from("direct:start")
// Prepare headers
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_OPERATION_GET))
.setHeader(CacheConstants.CACHE_KEY, constant("Ralph_Waldo_Emerson")).
.to("cache://TestCache1").
// Check if entry was not found
.choice().when(header(CacheConstants.CACHE_ELEMENT_WAS_FOUND).isNull()).
// If not found, get the payload and put it to cache
.to("cxf:bean:someHeavyweightOperation").
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_OPERATION_ADD))
.setHeader(CacheConstants.CACHE_KEY, constant("Ralph_Waldo_Emerson"))
.to("cache://TestCache1")
.end()
.to("direct:nextPhase");
|
Example 8: Checking for an entry in the Cache
Note: The CHECK command tests existence of an entry in the cache but doesn't place a message in the body.
Code Block |
---|
from("direct:start")
// Prepare headers
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_OPERATION_CHECK))
.setHeader(CacheConstants.CACHE_KEY, constant("Ralph_Waldo_Emerson")).
.to("cache://TestCache1").
// Check if entry was not found
.choice().when(header(CacheConstants.CACHE_ELEMENT_WAS_FOUND).isNull()).
// If not found, get the payload and put it to cache
.to("cxf:bean:someHeavyweightOperation").
.setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_OPERATION_ADD))
.setHeader(CacheConstants.CACHE_KEY, constant("Ralph_Waldo_Emerson"))
.to("cache://TestCache1")
.end();
|
Management of EHCache
EHCache has its own statistics and management from JMX.
Here's a snippet on how to expose them via JMX in a Spring application context:
Code Block | ||||
---|---|---|---|---|
| ||||
<bean id="ehCacheManagementService" class="net.sf.ehcache.management.ManagementService" init-method="init" lazy-init="false">
<constructor-arg>
<bean class="net.sf.ehcache.CacheManager" factory-method="getInstance"/>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.jmx.support.JmxUtils" factory-method="locateMBeanServer"/>
</constructor-arg>
<constructor-arg value="true"/>
<constructor-arg value="true"/>
<constructor-arg value="true"/>
<constructor-arg value="true"/>
</bean>
|
Of course you can do the same thing in straight Java:
Code Block | ||||
---|---|---|---|---|
| ||||
ManagementService.registerMBeans(CacheManager.getInstance(), mbeanServer, true, true, true, true);
|
You can get cache hits, misses, in-memory hits, disk hits, size stats this way. You can also change CacheConfiguration parameters on the fly.
Cache replication Camel 2.8+
The Camel Cache component is able to distribute a cache across server nodes using several different replication mechanisms including: RMI, JGroups, JMS and Cache Server.
There are two different ways to make it work:
1. You can configure ehcache.xml
manually
OR
2. You can configure these three options:
- cacheManagerFactory
- eventListenerRegistry
- cacheLoaderRegistry
Configuring Camel Cache replication using the first option is a bit of hard work as you have to configure all caches separately. So in a situation when the all names of caches are not known, using ehcache.xml
is not a good idea.
The second option is much better when you want to use many different caches as you do not need to define options per cache. This is because replication options are set per CacheManager
and per CacheEndpoint
. Also it is the only way when cache names are not know at the development phase.
Note |
---|
It might be useful to read the EHCache manual to get a better understanding of the Camel Cache replication mechanism. |
Example: JMS cache replication
JMS replication is the most powerful and secured replication method. Used together with Camel Cache replication makes it also rather simple.
An example is available on a separate page.
...