Chapter 56. EHCache Component (deprecated) Available as of Camel version 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. 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: <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> 56.1. URI format cache://cacheName[?options] You can append query options to the URI in the following format, ?option=value&option=#beanRef&... 56.2. Options The EHCache component supports 4 options, which are listed below. Name Description Default Type cacheManagerFactory (advanced) To use the given CacheManagerFactory for creating the CacheManager. By default the DefaultCacheManagerFactory is used. CacheManagerFactory configuration (common) Sets the Cache configuration CacheConfiguration configurationFile (common) Sets the location of the ehcache.xml file to load from classpath or file system. By default the file is loaded from classpath:ehcache.xml classpath:ehcache.xml String resolveProperty Placeholders (advanced) Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. true boolean The EHCache endpoint is configured using URI syntax: with the following path and query parameters: 56.2.1. Path Parameters (1 parameters): Name Description Default Type cacheName Required Name of the cache String 56.2.2. Query Parameters (19 parameters): Name Description Default Type diskExpiryThreadInterval Seconds (common) The number of seconds between runs of the disk expiry thread. long diskPersistent (common) Whether the disk store persists between restarts of the application. false boolean diskStorePath (common) Deprecated This parameter is ignored. CacheManager sets it using setter injection. String eternal (common) Sets whether elements are eternal. If eternal, timeouts are ignored and the element never expires. false boolean key (common) The default key to use. If a key is provided in the message header, then the key from the header takes precedence. String maxElementsInMemory (common) The number of elements that may be stored in the defined cache in memory. 1000 int memoryStoreEvictionPolicy (common) Which eviction strategy to use when maximum number of elements in memory is reached. The strategy defines which elements to be removed. LRU - Lest Recently Used LFU - Lest Frequently Used FIFO - First In First Out LFU MemoryStoreEviction Policy objectCache (common) 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. false boolean operation (common) The default cache operation to use. If an operation in the message header, then the operation from the header takes precedence. String overflowToDisk (common) Specifies whether cache may overflow to disk true boolean timeToIdleSeconds (common) The maximum amount of time between accesses before an element expires 300 long timeToLiveSeconds (common) The maximum time between creation time and when an element expires. Is used only if the element is not eternal 300 long bridgeErrorHandler (consumer) Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. false boolean exceptionHandler (consumer) To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. ExceptionHandler exchangePattern (consumer) Sets the exchange pattern when the consumer creates an exchange. ExchangePattern cacheLoaderRegistry (advanced) To configure cache loader using the CacheLoaderRegistry CacheLoaderRegistry cacheManagerFactory (advanced) To use a custom CacheManagerFactory for creating the CacheManager to be used by this endpoint. By default the CacheManagerFactory configured on the component is used. CacheManagerFactory eventListenerRegistry (advanced) To configure event listeners using the CacheEventListenerRegistry CacheEventListener Registry synchronous (advanced) Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). false boolean 56.3. Spring Boot Auto-Configuration The component supports 17 options, which are listed below. Name Description Default Type camel.component.cache.cache-manager-factory To use the given CacheManagerFactory for creating the CacheManager. By default the DefaultCacheManagerFactory is used. The option is a org.apache.camel.component.cache.CacheManagerFactory type. String camel.component.cache.configuration-file Sets the location of the ehcache.xml file to load from classpath or file system. By default the file is loaded from classpath:ehcache.xml classpath:ehcache.xml String camel.component.cache.configuration.cache-loader-registry To configure cache loader using the CacheLoaderRegistry CacheLoaderRegistry camel.component.cache.configuration.cache-name Name of the cache String camel.component.cache.configuration.disk-expiry-thread-interval-seconds The number of seconds between runs of the disk expiry thread. Long camel.component.cache.configuration.disk-persistent Whether the disk store persists between restarts of the application. false Boolean camel.component.cache.configuration.eternal Sets whether elements are eternal. If eternal, timeouts are ignored and the element never expires. false Boolean camel.component.cache.configuration.event-listener-registry To configure event listeners using the CacheEventListenerRegistry CacheEventListener Registry camel.component.cache.configuration.max-elements-in-memory The number of elements that may be stored in the defined cache in memory. 1000 Integer camel.component.cache.configuration.memory-store-eviction-policy Which eviction strategy to use when maximum number of elements in memory is reached. The strategy defines which elements to be removed. LRU - Lest Recently Used LFU - Lest Frequently Used FIFO - First In First Out MemoryStoreEviction Policy camel.component.cache.configuration.object-cache 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. false Boolean camel.component.cache.configuration.overflow-to-disk Specifies whether cache may overflow to disk true Boolean camel.component.cache.configuration.time-to-idle-seconds The maximum amount of time between accesses before an element expires 300 Long camel.component.cache.configuration.time-to-live-seconds The maximum time between creation time and when an element expires. Is used only if the element is not eternal 300 Long camel.component.cache.enabled Enable cache component true Boolean camel.component.cache.resolve-property-placeholders Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. true Boolean camel.component.cache.configuration.disk-store-path This parameter is ignored. CacheManager sets it using setter injection. String 56.4. Sending/Receiving Messages to/from the cache 56.4.1. Message Headers up to Camel 2.7 Header Description CACHE_OPERATION The operation to be performed on the cache. Valid options are * GET * CHECK * ADD * UPDATE * DELETE * DELETEALL GET and CHECK requires Camel 2.3 onwards. CACHE_KEY The cache key used to store the Message in the cache. The cache key is optional if the CACHE_OPERATION is DELETEALL 56.4.2. Message Headers Camel 2.8+ Header changes in Camel 2.8 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. Header Description CamelCacheOperation The operation to be performed on the cache. The valid options are * CamelCacheGet * CamelCacheCheck * CamelCacheAdd * CamelCacheUpdate * CamelCacheDelete * CamelCacheDeleteAll CamelCacheKey The cache key used to store the Message in the cache. The cache key is optional if the CamelCacheOperation is CamelCacheDeleteAll The CamelCacheAdd and CamelCacheUpdate operations support additional headers: Header Type Description CamelCacheTimeToLive Integer Camel 2.11: Time to live in seconds. CamelCacheTimeToIdle Integer Camel 2.11: Time to idle in seconds. CamelCacheEternal Boolean Camel 2.11: Whether the content is eternal. 56.4.3. 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 56.4.4. 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. 56.4.5. 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 56.5. Cache Usage Samples 56.5.1. Example 1: Configuring the cache from("cache://MyApplicationCache" + "?maxElementsInMemory=1000" + "&memoryStoreEvictionPolicy=" + "MemoryStoreEvictionPolicy.LFU" + "&overflowToDisk=true" + "&eternal=true" + "&timeToLiveSeconds=300" + "&timeToIdleSeconds=true" + "&diskPersistent=true" + "&diskExpiryThreadIntervalSeconds=300") 56.5.2. Example 2: Adding keys to the cache 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") } }; 56.5.3. Example 2: Updating existing keys in a cache 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") } }; 56.5.4. Example 3: Deleting existing keys in a cache 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") } }; 56.5.5. Example 4: Deleting all existing keys in a cache RouteBuilder builder = new RouteBuilder() { public void configure() { from("direct:start") .setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_DELETEALL)) .to("cache://TestCache1"); } }; 56.5.6. Example 5: Notifying any changes registering in a Cache to Processors and other Producers 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 } }) } }; 56.5.7. Example 6: Using Processors to selectively replace payload with cache values 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:"); //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:"); //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:"); } }; 56.5.8. Example 7: Getting an entry from the Cache 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"); 56.5.9. 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. 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(); 56.6. 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: <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: 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. 56.7. 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. 56.7.1. 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 .

Commands:
<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>
cache://cacheName[?options]
cache:cacheName
from("cache://MyApplicationCache" + "?maxElementsInMemory=1000" + "&memoryStoreEvictionPolicy=" + "MemoryStoreEvictionPolicy.LFU" + "&overflowToDisk=true" + "&eternal=true" + "&timeToLiveSeconds=300" + "&timeToIdleSeconds=true" + "&diskPersistent=true" + "&diskExpiryThreadIntervalSeconds=300")
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") } };
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") } };
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") } };
RouteBuilder builder = new RouteBuilder() { public void configure() { from("direct:start") .setHeader(CacheConstants.CACHE_OPERATION, constant(CacheConstants.CACHE_DELETEALL)) .to("cache://TestCache1"); } };
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 } }) } };
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"); } };
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");
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();
<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>
ManagementService.registerMBeans(CacheManager.getInstance(), mbeanServer, true, true, true, true);