create remote cache if does not exist during write and ignore remote cache if connection cannot be made

27 Views Asked by At

We are using Spring Cache abstration and Infinispan server as a remote cache in front of a slow service.

I have two requirements:

  • I would like to create the caches implicitly if they don't exist yet on the remote Infinispan server during access time based on a cache configuration template known by the Infinispan server.
  • If the connection to the remote Infinispan server cannot be established I am ok to call the slow service behind it.

Could you suggest how could I implement this?

The built-in @Cacheable annotation does not have support for this.

Should I use a custom annotation with an Aspect? For the second requirement within the Aspect I could handle the connection issue to remote Infinispan server.

1

There are 1 best solutions below

0
Zoltan Altfatter On

Introduced this simple CustomCacheable annotation

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomCacheable {

    // cache name
    String value() default "";
}

and with the following aspect I managed to fulfill both requirements:

@Component
@Aspect
public class CustomCacheableAspect {

    private static final Logger logger = LoggerFactory.getLogger(CustomCacheableAspect.class);

    private CacheManager cacheManager;

    public CustomCacheableAspect(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @Pointcut("@annotation(com.example.infinispandemo.custom.CustomCacheable)")
    public void customCacheablePointcut() {
    }

    @Around("customCacheablePointcut()")
    public Object allMethodCallsWithCustomCacheableAnnotationAdvice(ProceedingJoinPoint jp) throws Throwable {
        CustomCacheable a = findCustomCacheableAnnotation(jp);
        String cacheName = a.value();
        Object key = getKey(jp);

        RemoteCache<Object, Object> remoteCache;
        try {
            remoteCache = getOrCreateCache(cacheManager, cacheName);
        } catch (TransportException e) {
            logger.warn("Cache `{}` connection error `{}`", cacheName, e.getMessage());
            return jp.proceed();
        }

        Object cacheValue = remoteCache.get(key);
        if (cacheValue == null) {
            logger.warn("Cache `{}` miss for key `{}`", cacheName, key);
            Object result = jp.proceed();
            remoteCache.put(key, result);
            return result;
        } else {
            return cacheValue;
        }
    }

    private RemoteCache<Object, Object> getOrCreateCache(CacheManager cacheManager, String cacheName) {
        return ((SpringRemoteCacheManager) cacheManager).getNativeCacheManager()
                .administration().getOrCreateCache(cacheName, "default");
    }

    private CustomCacheable findCustomCacheableAnnotation(ProceedingJoinPoint jp) {
        return AnnotationUtils.findAnnotation(((MethodSignature) jp.getSignature()).getMethod(), CustomCacheable.class);
    }

    private Object getKey(ProceedingJoinPoint jp) {
        return jp.getArgs()[0];
    }
}