jcacheehcache-3

EhCache 3 how to get the alias (name) of a Cache from a CacheEvent?


I have a generic listener for most of my caches and I do some logging when an event occurs. The problem is that I don't know which cache is behind the event that I caught. How do I get the cache's alias (i.e. name) ?

I have:

The configuration class (it reads in the .xml file ehcache.xml)

@Configuration
@EnableCaching
public class CacheConfig {

@Autowired
private javax.cache.CacheManager cacheManager;

}

application.yml

spring:
  cache:
    jcache:
      config: classpath:ehcache.xml

ehcache.xml (in src/main/resources)

...
<cache alias="myCache">
    <listeners>
        <listener>
            <class>com.iznogoud.cache.DefaultListener</class>
            <event-firing-mode>ASYNCHRONOUS</event-firing-mode>
            <event-ordering-mode>UNORDERED</event-ordering-mode>
            <events-to-fire-on>CREATED</events-to-fire-on>
            <events-to-fire-on>EXPIRED</events-to-fire-on>
            <events-to-fire-on>EVICTED</events-to-fire-on>
            <events-to-fire-on>REMOVED</events-to-fire-on>
            <events-to-fire-on>UPDATED</events-to-fire-on>
        </listener>
    </listeners>
    <expiry>
        <ttl unit="seconds">10</ttl>
    </expiry>
    <heap unit="entries">10000</heap>
</cache>

My generic Listener class, com.iznogoud.cache.DefaultListener:

@Component
public class DefaultListener implements CacheEventListener<Object, Object> {

    private static final Logger LOGGER... 

    public DefaultListener() {}

    @Override
    public void onEvent(CacheEvent<?, ?> cacheEvent) {
        String cacheAlias = "dont-know!";
        String key = cacheEvent.getKey().toString();
        String = cacheEvent.getOldValue()==null?"null":cacheEvent.getOldValue().toString();
        String = cacheEvent.getNewValue()==null?"null":cacheEvent.getNewValue().toString();
        LOGGER.debug("Cache {}, EventType: {} : Key: {} |  | value {} -> {}",
                cacheAlias, cacheEvent.getType(), key, oldValue, newValue);
    }

Solution

  • Here's a somewhat-of-a-hack answer, but it works under I'm-testing-it-myself conditions:

    In the @Configuration file where you define the cache manager add an init() method that constructs a map of the caches, and make the map public.

    @Configuration
    @EnableCaching
    public class CacheConfig {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(CacheConfig.class);
    
        @Autowired
        private javax.cache.CacheManager cacheManager;  
    
        /** a mapping that enables Cache Listeners to get the name of the Cache when an event arrives **/
        public static HashMap<String, String> cacheNamesMap;
    
        /** ehCache Listeners don't know which cache they are dealing with.  (unless you have a listener class for each cache, ugh)
         But the cache manager here has all the aliases.
         So, make a map available between the instance of a cache (via .toString()) and it's name.
         The listeners use this map to find the alias of the cache that triggered the event.
         */
        @PostConstruct
        private void init() {
            cacheNamesMap = new HashMap<>();
            List<String> cacheNames = new ArrayList<String>();
            for (String nextName : cacheManager.getCacheNames()) {
                // use a key based on the underlying ehCache class, not the jCache class, the listeners are ehCache specific
                Cache nextCache = cacheManager.getCache(nextName).unwrap(org.ehcache.Cache.class);
                cacheNamesMap.put(nextCache.toString(), nextName);
            }
            LOGGER.debug("{} caches in cacheNamesMap.", cacheNamesMap.size());
            LOGGER.debug("  keys: {}", cacheNamesMap.keySet());
        }
    

    Then access the map in your listener.

     @Override
     public void onEvent(CacheEvent<?, ?> cacheEvent) {
         Cache cache =  cacheEvent.getSource();
         String cacheAlias = CacheConfig.cacheNamesMap.get(cache.toString());  
         ...
    

    Maybe it's not the most industrial waterproof solution but it works for me. getSource() is, unfortunately, deprecated.