From fbe97748900f2c899fabeb881fd15d7b318c3326 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 30 Mar 2015 10:39:46 +0200 Subject: [PATCH] Use spring.cache.config with JCache According to the spec, specifying a custom URI when retrieving a `javax.cache.CacheManager` might be used as a way to transmit the location of a custom configuration file to initialize the underlying cache manager. If `spring.cache.config` is set, we use that information to retrieve a CacheManager with that configuration file. Unfortunately, hazelcast does not support this feature so we are setting the property key it expects instead. See https://github.com/hazelcast/hazelcast/issues/4943 Closes gh-2743 --- .../cache/JCacheCacheConfiguration.java | 34 +++++++++--- .../cache/CacheAutoConfigurationTests.java | 55 +++++++++++++++++-- .../cache/support/MockCachingProvider.java | 4 +- 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java index 0cdce464f7..27f3a9d5b5 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java @@ -16,8 +16,10 @@ package org.springframework.boot.autoconfigure.cache; +import java.io.IOException; import java.util.Iterator; import java.util.List; +import java.util.Properties; import javax.cache.CacheManager; import javax.cache.Caching; import javax.cache.configuration.MutableConfiguration; @@ -37,6 +39,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; +import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -64,9 +67,8 @@ class JCacheCacheConfiguration { private List cacheManagerCustomizers; @Bean - public JCacheCacheManager cacheManager() { - CacheManager cacheManager = createCacheManager(this.cacheProperties.getJcache() - .getProvider()); + public JCacheCacheManager cacheManager() throws IOException { + CacheManager cacheManager = createCacheManager(); List cacheNames = this.cacheProperties.getCacheNames(); if (!CollectionUtils.isEmpty(cacheNames)) { for (String cacheName : cacheNames) { @@ -77,11 +79,29 @@ class JCacheCacheConfiguration { return new JCacheCacheManager(cacheManager); } - private CacheManager createCacheManager(String cachingProvider) { - if (StringUtils.hasText(cachingProvider)) { - return Caching.getCachingProvider(cachingProvider).getCacheManager(); + private CacheManager createCacheManager() throws IOException { + CachingProvider cachingProvider = getCachingProvider(this.cacheProperties + .getJcache().getProvider()); + Resource configLocation = this.cacheProperties.resolveConfigLocation(); + if (configLocation != null) { + return cachingProvider.getCacheManager(configLocation.getURI(), + cachingProvider.getDefaultClassLoader(), createCacheManagerProperties(configLocation)); } - return Caching.getCachingProvider().getCacheManager(); + return cachingProvider.getCacheManager(); + } + + private CachingProvider getCachingProvider(String cachingProviderFqn) { + if (StringUtils.hasText(cachingProviderFqn)) { + return Caching.getCachingProvider(cachingProviderFqn); + } + return Caching.getCachingProvider(); + } + + private Properties createCacheManagerProperties(Resource configLocation) throws IOException { + Properties properties = new Properties(); + // Hazelcast does not use the URI as a mean to specify a custom config. + properties.setProperty("hazelcast.config.location", configLocation.getURI().toString()); + return properties; } private javax.cache.configuration.Configuration getDefaultCacheConfiguration() { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java index ee3e5f0f75..a011a63da4 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.cache; +import java.io.IOException; import java.util.Collection; import java.util.Collections; @@ -50,6 +51,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.core.RedisTemplate; @@ -250,6 +253,30 @@ public class CacheAutoConfigurationTests { "spring.cache.jcache.provider=" + wrongCachingProviderFqn); } + @Test + public void jCacheCacheWithConfig() throws IOException { + String cachingProviderFqn = MockCachingProvider.class.getName(); + String configLocation = "org/springframework/boot/autoconfigure/cache/hazelcast-specific.xml"; + load(JCacheCustomConfiguration.class, "spring.cache.type=jcache", + "spring.cache.jcache.provider=" + cachingProviderFqn, + "spring.cache.config=" + configLocation); + JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class); + Resource configResource = new ClassPathResource(configLocation); + assertThat(cacheManager.getCacheManager().getURI(), is(configResource.getURI())); + } + + @Test + public void jCacheCacheWithWrongConfig() { + String cachingProviderFqn = MockCachingProvider.class.getName(); + String configLocation = "org/springframework/boot/autoconfigure/cache/does-not-exist.xml"; + thrown.expect(BeanCreationException.class); + thrown.expectMessage("spring.cache.config"); + thrown.expectMessage(configLocation); + load(JCacheCustomConfiguration.class, "spring.cache.type=jcache", + "spring.cache.jcache.provider=" + cachingProviderFqn, + "spring.cache.config=" + configLocation); + } + @Test public void ehCacheCacheWithCaches() { load(DefaultCacheConfiguration.class, "spring.cache.type=ehcache"); @@ -268,7 +295,7 @@ public class CacheAutoConfigurationTests { } @Test - public void ehCacheCacheWithLocation() { + public void ehCacheCacheWithConfig() { load(DefaultCacheConfiguration.class, "spring.cache.type=ehcache", "spring.cache.config=cache/ehcache-override.xml"); EhCacheCacheManager cacheManager = null; @@ -296,7 +323,7 @@ public class CacheAutoConfigurationTests { } @Test - public void hazelcastCacheWithLocation() { + public void hazelcastCacheWithConfig() { load(DefaultCacheConfiguration.class, "spring.cache.type=hazelcast", "spring.cache.config=org/springframework/boot/autoconfigure/cache/hazelcast-specific.xml"); HazelcastCacheManager cacheManager = validateCacheManager(HazelcastCacheManager.class); @@ -306,12 +333,11 @@ public class CacheAutoConfigurationTests { } @Test - public void hazelcastWithWrongLocation() { + public void hazelcastWithWrongConfig() { this.thrown.expect(BeanCreationException.class); this.thrown.expectMessage("foo/bar/unknown.xml"); load(DefaultCacheConfiguration.class, "spring.cache.type=hazelcast", "spring.cache.config=foo/bar/unknown.xml"); - System.out.println(this.context.getBean(CacheManager.class).getClass()); } @Test @@ -333,6 +359,27 @@ public class CacheAutoConfigurationTests { } } + @Test + public void hazelcastAsJCacheWithConfig() throws IOException { + String cachingProviderFqn = HazelcastCachingProvider.class.getName(); + String configLocation = "org/springframework/boot/autoconfigure/cache/hazelcast-specific.xml"; + JCacheCacheManager cacheManager = null; + try { + load(DefaultCacheConfiguration.class, "spring.cache.type=jcache", + "spring.cache.jcache.provider=" + cachingProviderFqn, + "spring.cache.config="+configLocation); + cacheManager = validateCacheManager(JCacheCacheManager.class); + + Resource configResource = new ClassPathResource(configLocation); + assertThat(cacheManager.getCacheManager().getURI(), is(configResource.getURI())); + } + finally { + if (cacheManager != null) { + cacheManager.getCacheManager().close(); + } + } + } + @Test public void jCacheCacheWithCachesAndCustomizer() { String cachingProviderFqn = HazelcastCachingProvider.class.getName(); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/support/MockCachingProvider.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/support/MockCachingProvider.java index 156c9179be..fc51d34f79 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/support/MockCachingProvider.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/support/MockCachingProvider.java @@ -48,6 +48,8 @@ public class MockCachingProvider implements CachingProvider { public CacheManager getCacheManager(URI uri, ClassLoader classLoader, Properties properties) { CacheManager cacheManager = mock(CacheManager.class); + given(cacheManager.getURI()).willReturn(uri); + given(cacheManager.getClassLoader()).willReturn(classLoader); final Map caches = new HashMap(); given(cacheManager.getCacheNames()).willReturn(caches.keySet()); given(cacheManager.getCache(anyString())).willAnswer(new Answer() { @@ -74,7 +76,7 @@ public class MockCachingProvider implements CachingProvider { @Override public ClassLoader getDefaultClassLoader() { - return null; + return mock(ClassLoader.class); } @Override