3

I want to consume data from web service and put it in camel eh-cache. later i want to use this cache outside camel context through CacheManager. I am not finding any way to do it.

In below code I have skipped consumption of web service and used data from Map and provided it to eh-cache but I am not able to access this cache using CacheManager.

CamelRouter class

package com.camel;


import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.ehcache.EhcacheConstants;
import org.apache.camel.main.Main;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.Configuration;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.xml.XmlConfiguration;

public class Test {

    private static Main main;

    public static void main(String[] args) throws Exception {

        main = new Main();
        main.addRouteBuilder(new RouteBuilder() {

            @Override
            public void configure() throws Exception {
                from("timer:foo?period=5s&repeatCount=1")
                .process(exchange ->{
                    Map<String, String> inputMap = new HashMap<>();
                    inputMap.put("name", "murli");
                    inputMap.put("lastname", "hiware");
                    inputMap.put("city", "pune");
                    exchange.getIn().setBody(inputMap);
                    exchange.getIn().setHeader("CamelEhcacheAction", EhcacheConstants.ACTION_PUT_ALL);
                })
                .to("ehcache://testCache?configUri=ehcache.xml&keyType=java.lang.String&valueType=java.lang.String")
                .process(exchange -> {
                    URL myUrl = getClass().getResource("/ehcache.xml"); 
                    Configuration xmlConfig = new XmlConfiguration(myUrl); 
                    CacheManager myCacheManager = CacheManagerBuilder.newCacheManager(xmlConfig); 
                    myCacheManager.init();
                    //here I want to access already created testCache component but it is creating new one.
                    Cache<String, String> cache = myCacheManager.getCache("testCache", String.class, String.class);
                    System.out.println("Cache Element:"+cache.get("name"));
                    System.out.println("Exchange Message:"+exchange.getIn().getBody());

                });
            }
        });

         main.run();
    }

}

ehcache config file

<config
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns='http://www.ehcache.org/v3'
    xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">

  <cache alias="testCache"> 
    <key-type>java.lang.String</key-type> 
    <value-type>java.lang.String</value-type> 
    <resources>
      <heap unit="entries">2000</heap> 
      <offheap unit="MB">100</offheap> 
    </resources>
  </cache>

  <cache-template name="myDefaults"> 
    <key-type>java.lang.Long</key-type>
    <value-type>java.lang.String</value-type>
    <heap unit="entries">200</heap>
  </cache-template>

  <cache alias="bar" uses-template="myDefaults"> 
    <key-type>java.lang.Number</key-type>
  </cache>

  <cache alias="simpleCache" uses-template="myDefaults" /> 

</config>

please let me know the use case I am trying to achieve is possible with camel eh-cache or not?

Murli
  • 1,258
  • 9
  • 20

4 Answers4

4

You should normally by able to retrieve a value with a from("ehcache://...).

However, I will assume you really want to access the cache or cache manager.

This is the way to do it:

public static void main(String[] args) throws Exception {
    URL url = App.class.getResource("/ehcache.xml");
    Configuration xmlConfig = new XmlConfiguration(url);

    CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
    cacheManager.init();

    Main main = new Main();
    main.bind("cacheManager", cacheManager);

    main.addRouteBuilder(new RouteBuilder() {

        @Override
        public void configure() throws Exception {
            from("timer:foo?period=5s&repeatCount=1")
                .process(exchange ->{
                    Map<String, String> inputMap = new HashMap<>();
                    inputMap.put("name", "murli");
                    inputMap.put("lastname", "hiware");
                    inputMap.put("city", "pune");
                    exchange.getIn().setBody(inputMap);
                    exchange.getIn().setHeader("CamelEhcacheAction", EhcacheConstants.ACTION_PUT_ALL);
                })
                .to("ehcache://testCache?cacheManager=#cacheManager&keyType=java.lang.String&valueType=java.lang.String")
                .process(exchange -> {
                    //here I want to access already created testCache component but it is creating new one.
                    Cache<String, String> cache = cacheManager.getCache("testCache", String.class, String.class);
                    System.out.println("Cache Element:"+cache.get("name"));
                    System.out.println("Exchange Message:"+exchange.getIn().getBody());

                });
        }
    });

    main.run();
}
Henri
  • 5,551
  • 1
  • 22
  • 29
3

What you are looking for is:

  • either a repository of CacheManager that you can access from anywhere, including from the Camel context
  • or you need to find a way to expose the Cache or CacheManager out of the context.

The first one was the default for Ehcache 2.x, it was by design removed from Ehcache 3.x. Sadly I do not know Camel well enough to recommend either way as the best approach.

Louis Jacomet
  • 13,661
  • 2
  • 34
  • 43
2

You can set the cache manager using and uri like:

    to("ehcache:myCache?cacheManager=#myCacheManager")

Where myCacheManager is a reference of a bean you on the camel registry, for a sample, have a look at :

Luca Burgazzoli
  • 1,216
  • 7
  • 9
0

I'd like to share the approach, when the Camel-context cache was reached from the Spring Boot @Service. As the result, the REST API makes possible to retrieve the latest value, streamed through the route:

First of all, we do add the cache as additional destination point of the route, however, we transform the incoming data to make it a String object explicitly, that is done in process part before the last to():

  from(
                getMqttRouteConfiguration(
                        sourceId, mqttHost, mqttTopic, mqttPort, mqttProtocol, authenticated,
                        username, password, mqttVersion, maxReadRate, qualityOfService
                )
        )
                .to("log:camel.proxy?level=INFO&groupInterval=500000")
                .to(String.format("kafka:%s?brokers=%s", sourceId, kafkaBrokerUrls))
                .process(new Processor() {
                    @Override
                    public void process(Exchange exchange) throws Exception {
                     exchange.getIn().setBody(exchange.getIn().getBody(String.class));
                     exchange.getIn().setHeader("CamelCacheKey",sourceId);
                     exchange.getIn().setHeader("CamelCacheOperation","Update");
                    }
                })
                .to(String.format("cache://%s?maxElementsInMemory=10&eternal=true", sourceId))
                .routeId(sourceId);

At the @Service we call for the camelContext and then retrieve the needed component with "cache" value:

public Optional<String> cachedLastValue(String key) {
        CacheManager cacheManager = ((CacheComponent) camelContext.getComponent("cache")).getCacheManagerFactory().getInstance();
        Cache cache = cacheManager.getCache(key);
        if (cache != null) {
            Element valueElement = cache.
                    get(key);
            if (valueElement != null) {
                String value = (String) (valueElement.
                        getObjectValue());
                return Optional.of(value);
            } else {
                logger.warn("Cached value for {} topic was requested, but can not be retrieved from the cache: {} with key: {}", key, key, key);
            }
        } else {
            logger.info("Cached value for {} topic was requested, but not yet recorded from the source", key);
        }
        return Optional.empty();
    }

And thus we reach CacheManager and Cache objects, that allow us to look into the needed cache name and retrieve the last value left here.

After this solution it is still not clear, can we use the same approach for storing about 10 values in cache and retrieve all of them. Also, it was not clear why it was not ok without explicit call of

                     exchange.getIn().setBody(exchange.getIn().getBody(String.class));
                     exchange.getIn().setHeader("CamelCacheKey",sourceId);
                     exchange.getIn().setHeader("CamelCacheOperation","Update");

where I manually place the String object to exchange body before the putting it into the cache, and explicit set of the Headers (I believe that they should be added by the Apache Camel Ehcache by default, but I had to add them explicitly).

Eljah
  • 4,188
  • 4
  • 41
  • 85