package org.infinispan.jcache.annotation;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.cache.Cache;
import javax.cache.Caching;
import javax.cache.annotation.CacheInvocationContext;
import javax.cache.annotation.CacheResolver;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import org.infinispan.cdi.common.util.BeanManagerProvider;
import org.infinispan.cdi.embedded.InfinispanExtensionEmbedded;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.infinispan.jcache.embedded.JCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
/**
* Injected cache resolver for situations where caches and/or cache managers
* are injected into the CDI beans. In these situations, bridging is required
* in order to bridge between the Infinispan based caches and the JCache
* cache instances which is what it's expected by the specification cache
* resolver.
*
* @author Galder ZamarreƱo
* @since 5.3
*/
@ApplicationScoped
public class InjectedCacheResolver implements CacheResolver {
private EmbeddedCacheManager defaultCacheManager;
private final Map<EmbeddedCacheManager, JCacheManager> jcacheManagers = new HashMap<>();
private JCacheManager defaultJCacheManager;
// for proxy.
public InjectedCacheResolver() {
}
@Inject
public InjectedCacheResolver(final InfinispanExtensionEmbedded extension, final BeanManager beanManager) {
final Set<InfinispanExtensionEmbedded.InstalledCacheManager> installedCacheManagers = extension.getInstalledEmbeddedCacheManagers(beanManager);
for (final InfinispanExtensionEmbedded.InstalledCacheManager installedCacheManager : installedCacheManagers) {
final JCacheManager jcacheManager = toJCacheManager(installedCacheManager.getCacheManager());
this.jcacheManagers.put(installedCacheManager.getCacheManager(), jcacheManager);
}
initializeDefaultCacheManagers();
}
private void initializeDefaultCacheManagers() {
defaultCacheManager = getBeanReference(EmbeddedCacheManager.class);
if (jcacheManagers.containsKey(defaultCacheManager)) {
defaultJCacheManager = jcacheManagers.get(defaultCacheManager);
} else {
defaultJCacheManager = toJCacheManager(defaultCacheManager);
jcacheManagers.put(defaultCacheManager, defaultJCacheManager);
}
}
private JCacheManager toJCacheManager(final EmbeddedCacheManager cacheManager) {
final GlobalConfiguration globalCfg = cacheManager.getCacheManagerConfiguration();
final String name = globalCfg.globalJmxStatistics().cacheManagerName();
return new JCacheManager(URI.create(name), cacheManager, Caching.getCachingProvider());
}
@Override
public <K, V> Cache<K, V> resolveCache(final CacheInvocationContext<? extends Annotation> cacheInvocationContext) {
Contracts.assertNotNull(cacheInvocationContext, "cacheInvocationContext parameter must not be null");
final String cacheName = cacheInvocationContext.getCacheName();
// If the cache name is empty the default cache of the default cache manager is returned.
if (cacheName.trim().isEmpty()) {
return getCacheFromDefaultCacheManager(cacheName);
}
// Iterate on all cache managers because the cache used by the
// interceptor could use a specific cache manager.
for (final EmbeddedCacheManager cm : jcacheManagers.keySet()) {
final Set<String> cacheNames = cm.getCacheNames();
for (final String name : cacheNames) {
if (name.equals(cacheName)) {
final JCacheManager jcacheManager = jcacheManagers.get(cm);
final Cache<K, V> cache = jcacheManager.getCache(cacheName);
if (cache != null)
return cache;
return jcacheManager.getOrCreateCache(
cacheName, cm.<K, V>getCache(cacheName).getAdvancedCache());
}
}
}
// If the cache has not been defined in the default cache manager
// or in a specific one a new cache is created in the default
// cache manager with the default configuration.
return getCacheFromDefaultCacheManager(cacheName);
}
private <K, V> Cache<K, V> getCacheFromDefaultCacheManager(final String cacheName) {
final Configuration defaultInjectedConfiguration = getBeanReference(Configuration.class);
defaultCacheManager.defineConfiguration(cacheName, defaultInjectedConfiguration);
return defaultJCacheManager.getOrCreateCache(cacheName, defaultCacheManager.<K, V>getCache(cacheName)
.getAdvancedCache());
}
private BeanManager getBeanManager() {
return BeanManagerProvider.getInstance().getBeanManager();
}
@SuppressWarnings("unchecked")
private <T> T getBeanReference(final Class<T> beanType) {
final BeanManager bm = getBeanManager();
final Iterator<Bean<?>> iterator = bm.getBeans(beanType).iterator();
if (!iterator.hasNext()) {
throw new IllegalStateException(String.format(
"Default bean of type %s not found.", beanType.getName()));
}
final Bean<?> configurationBean = iterator.next();
final CreationalContext<?> createCreationalContext = bm.createCreationalContext(configurationBean);
return (T) bm.getReference(configurationBean, beanType, createCreationalContext);
}
}