package org.infinispan.jcache; import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.WeakHashMap; import javax.cache.CacheManager; import javax.cache.spi.CachingProvider; import org.infinispan.commons.logging.LogFactory; import org.infinispan.jcache.logging.Log; /** * Shared behavior for the embedded and client-server implementations. * * @author Vladimir Blagojevic * @author Galder ZamarreƱo */ public abstract class AbstractJCachingProvider implements CachingProvider { private static final Log log = LogFactory.getLog(AbstractJCachingProvider.class, Log.class); private static final boolean trace = log.isTraceEnabled(); /** * Keeps track of cache managers. Each cache manager has to be tracked * based on its name and class loader. So, you could be have cache managers * registered with the same name but different class loaders, resulting in * different cache manager instances. * * A solution based around weak value references to cache managers won't * work here, because if the user does not have any references to the * cache managers, these would disappear from the map. Users are not * required to keep strong references to cache managers. They can simply * get cache manager references via * {@link javax.cache.spi.CachingProvider#getCacheManager()}. * * So, the only possible way to avoid leaking cache managers is to have a * weak key hash map keyed on class loader. So when no other hard * references to the class loader are kept, the cache manager can be * garbage collected and its {@link #finalize()} method can be called * if the user forgot to shut down the cache manager. */ private final Map<ClassLoader, Map<URI, CacheManager>> cacheManagers = new WeakHashMap<ClassLoader, Map<URI, CacheManager>>(); @Override public CacheManager getCacheManager(URI uri, ClassLoader classLoader, Properties properties) { URI globalUri = uri == null ? getDefaultURI() : uri; ClassLoader globalClassLoader = classLoader == null ? getDefaultClassLoader() : classLoader; Properties globalProperties = properties == null ? new Properties() : properties; synchronized (cacheManagers) { Map<URI, CacheManager> map = cacheManagers.get(globalClassLoader); if (map == null) { if (trace) log.tracef("No cache managers registered under '%s'", globalUri); map = new HashMap<URI, CacheManager>(); cacheManagers.put(globalClassLoader, map); } CacheManager cacheManager = map.get(globalUri); if (cacheManager == null || cacheManager.isClosed()) { // Not found or stopped, create cache manager and add to collection cacheManager = createCacheManager(globalClassLoader, globalUri, globalProperties); if (trace) log.tracef("Created '%s' cache manager", globalUri); map.put(globalUri, cacheManager); } return cacheManager; } } @Override public CacheManager getCacheManager(URI uri, ClassLoader classLoader) { return getCacheManager(uri, classLoader, getDefaultProperties()); } @Override public ClassLoader getDefaultClassLoader() { return getClass().getClassLoader(); } @Override public Properties getDefaultProperties() { return null; } @Override public CacheManager getCacheManager() { return getCacheManager(getDefaultURI(), getDefaultClassLoader()); } @Override public void close() { synchronized (cacheManagers) { for (Map<URI, CacheManager> map : cacheManagers.values()) close(map); cacheManagers.clear(); if (trace) log.tracef("All cache managers have been removed"); } } @Override public void close(ClassLoader classLoader) { close(null, classLoader); } @Override public void close(URI uri, ClassLoader classLoader) { synchronized (cacheManagers) { if (uri != null) { Map<URI, CacheManager> map = cacheManagers.get(classLoader); if (map != null) { CacheManager cacheManager = map.remove(uri); if (map.isEmpty()) cacheManagers.remove(classLoader); if (cacheManager != null) cacheManager.close(); } } else { Map<URI, CacheManager> cacheManagersToClose = cacheManagers.remove(classLoader); if (cacheManagersToClose != null) close(cacheManagersToClose); } } } private void close(Map<URI, CacheManager> map) { for (CacheManager cacheManager : map.values()) { cacheManager.close(); if (trace) log.tracef("Shutdown cache manager '%s'", cacheManager.getURI()); } } protected abstract CacheManager createCacheManager( ClassLoader classLoader, URI uri, Properties properties); }