diff --git a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java
index 212f5d6e0d..ec7dabdddc 100644
--- a/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java
+++ b/spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java
@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
*
* @author Costin Leau
* @author Juergen Hoeller
+ * @author Stephane Nicoll
* @since 3.1
*/
public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManager {
@@ -86,17 +87,14 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
}
@Override
- public Cache getCache(String name) {
- Cache cache = super.getCache(name);
- if (cache == null) {
- // Check the EhCache cache again (in case the cache was added at runtime)
- Ehcache ehcache = getCacheManager().getEhcache(name);
- if (ehcache != null) {
- addCache(new EhCacheCache(ehcache));
- cache = super.getCache(name); // potentially decorated
- }
+ protected Cache getMissingCache(String name) {
+ // check the EhCache cache again
+ // (in case the cache was added at runtime)
+ Ehcache ehcache = getCacheManager().getEhcache(name);
+ if (ehcache != null) {
+ return new EhCacheCache(ehcache);
}
- return cache;
+ return null;
}
}
diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java
index 453f87828b..9c324efcdd 100644
--- a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java
+++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java
@@ -31,6 +31,7 @@ import org.springframework.cache.transaction.AbstractTransactionSupportingCacheM
*
Note: This class has been updated for JCache 1.0, as of Spring 4.0.
*
* @author Juergen Hoeller
+ * @author Stephane Nicoll
* @since 3.2
*/
public class JCacheCacheManager extends AbstractTransactionSupportingCacheManager {
@@ -108,17 +109,13 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
}
@Override
- public Cache getCache(String name) {
- Cache cache = super.getCache(name);
- if (cache == null) {
- // Check the JCache cache again (in case the cache was added at runtime)
- javax.cache.Cache jcache = getCacheManager().getCache(name);
- if (jcache != null) {
- addCache(new JCacheCache(jcache, isAllowNullValues()));
- cache = super.getCache(name); // potentially decorated
- }
+ protected Cache getMissingCache(String name) {
+ // Check the JCache cache again (in case the cache was added at runtime)
+ javax.cache.Cache jcache = getCacheManager().getCache(name);
+ if (jcache != null) {
+ return new JCacheCache(jcache, isAllowNullValues());
}
- return cache;
+ return null;
}
}
diff --git a/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheManagerTests.java b/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheManagerTests.java
new file mode 100644
index 0000000000..eb75558d45
--- /dev/null
+++ b/spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheManagerTests.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cache.ehcache;
+
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.config.Configuration;
+import org.junit.After;
+import org.junit.Before;
+import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManagerTests;
+
+/**
+ * @author Stephane Nicoll
+ */
+public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests {
+
+ private CacheManager nativeCacheManager;
+ private EhCacheCacheManager cacheManager;
+ private EhCacheCacheManager transactionalCacheManager;
+
+ @Before
+ public void setup() {
+ nativeCacheManager = new CacheManager(new Configuration().name("EhCacheCacheManagerTests")
+ .defaultCache(new CacheConfiguration("default", 100)));
+ addNativeCache(CACHE_NAME);
+
+ cacheManager = new EhCacheCacheManager(nativeCacheManager);
+ cacheManager.setTransactionAware(false);
+ cacheManager.afterPropertiesSet();
+
+ transactionalCacheManager = new EhCacheCacheManager(nativeCacheManager);
+ transactionalCacheManager.setTransactionAware(true);
+ transactionalCacheManager.afterPropertiesSet();
+ }
+
+ @After
+ public void tearDown() {
+ nativeCacheManager.shutdown();
+ }
+
+
+ @Override
+ protected EhCacheCacheManager getCacheManager(boolean transactionAware) {
+ if (transactionAware) {
+ return transactionalCacheManager;
+ } else {
+ return cacheManager;
+ }
+ }
+
+ @Override
+ protected Class extends org.springframework.cache.Cache> getCacheType() {
+ return EhCacheCache.class;
+ }
+
+ @Override
+ protected void addNativeCache(String cacheName) {
+ nativeCacheManager.addCache(cacheName);
+ }
+
+ @Override
+ protected void removeNativeCache(String cacheName) {
+ nativeCacheManager.removeCache(cacheName);
+ }
+}
diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheCacheManagerTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheCacheManagerTests.java
new file mode 100644
index 0000000000..c60798b88c
--- /dev/null
+++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheCacheManagerTests.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cache.jcache;
+
+import static org.mockito.BDDMockito.*;
+import static org.mockito.Mockito.mock;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManagerTests;
+
+/**
+ * @author Stephane Nicoll
+ */
+public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests {
+
+ private CacheManagerMock cacheManagerMock;
+ private JCacheCacheManager cacheManager;
+ private JCacheCacheManager transactionalCacheManager;
+
+ @Before
+ public void setupOnce() {
+ cacheManagerMock = new CacheManagerMock();
+ cacheManagerMock.addCache(CACHE_NAME);
+
+ cacheManager = new JCacheCacheManager(cacheManagerMock.getCacheManager());
+ cacheManager.setTransactionAware(false);
+ cacheManager.afterPropertiesSet();
+
+ transactionalCacheManager = new JCacheCacheManager(cacheManagerMock.getCacheManager());
+ transactionalCacheManager.setTransactionAware(true);
+ transactionalCacheManager.afterPropertiesSet();
+ }
+
+
+ @Override
+ protected JCacheCacheManager getCacheManager(boolean transactionAware) {
+ if (transactionAware) {
+ return transactionalCacheManager;
+ } else {
+ return cacheManager;
+ }
+ }
+
+ @Override
+ protected Class extends org.springframework.cache.Cache> getCacheType() {
+ return JCacheCache.class;
+ }
+
+ @Override
+ protected void addNativeCache(String cacheName) {
+ cacheManagerMock.addCache(cacheName);
+ }
+
+ @Override
+ protected void removeNativeCache(String cacheName) {
+ cacheManagerMock.removeCache(cacheName);
+ }
+
+ private static class CacheManagerMock {
+
+ private final List cacheNames;
+ private final CacheManager cacheManager;
+
+ private CacheManagerMock() {
+ this.cacheNames = new ArrayList();
+ this.cacheManager = mock(CacheManager.class);
+ given(cacheManager.getCacheNames()).willReturn(cacheNames);
+ }
+
+ private CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void addCache(String name) {
+ cacheNames.add(name);
+ Cache cache = mock(Cache.class);
+ given(cache.getName()).willReturn(name);
+ given(cacheManager.getCache(name)).willReturn(cache);
+ }
+
+ public void removeCache(String name) {
+ cacheNames.remove(name);
+ given(cacheManager.getCache(name)).willReturn(null);
+ }
+ }
+}
diff --git a/spring-context-support/src/test/java/org/springframework/cache/transaction/AbstractTransactionSupportingCacheManagerTests.java b/spring-context-support/src/test/java/org/springframework/cache/transaction/AbstractTransactionSupportingCacheManagerTests.java
new file mode 100644
index 0000000000..39fb0db58d
--- /dev/null
+++ b/spring-context-support/src/test/java/org/springframework/cache/transaction/AbstractTransactionSupportingCacheManagerTests.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cache.transaction;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+
+/**
+ * Shared tests for {@link CacheManager} that inherit from
+ * {@link AbstractTransactionSupportingCacheManager}.
+ *
+ * @author Stephane Nicoll
+ */
+public abstract class AbstractTransactionSupportingCacheManagerTests {
+
+ public static final String CACHE_NAME = "testCacheManager";
+
+ @Rule
+ public final TestName name = new TestName();
+
+
+ /**
+ * Returns the {@link CacheManager} to use.
+ *
+ * @param transactionAware if the requested cache manager should be aware
+ * of the transaction
+ * @return the cache manager to use
+ * @see org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware(boolean)
+ */
+ protected abstract T getCacheManager(boolean transactionAware);
+
+ /**
+ * Returns the expected concrete type of the cache.
+ */
+ protected abstract Class extends Cache> getCacheType();
+
+ /**
+ * Adds a cache with the specified name to the native manager.
+ */
+ protected abstract void addNativeCache(String cacheName);
+
+ /**
+ * Removes the cache with the specified name from the native manager.
+ */
+ protected abstract void removeNativeCache(String cacheName);
+
+ @Test
+ public void getOnExistingCache() {
+ assertThat(getCacheManager(false).getCache(CACHE_NAME), is(instanceOf(getCacheType())));
+ }
+
+ @Test
+ public void getOnNewCache() {
+ T cacheManager = getCacheManager(false);
+ String cacheName = name.getMethodName();
+ addNativeCache(cacheName);
+ assertFalse(cacheManager.getCacheNames().contains(cacheName));
+ try {
+ assertThat(cacheManager.getCache(cacheName),
+ is(instanceOf(getCacheType())));
+ assertTrue(cacheManager.getCacheNames().contains(cacheName));
+ } finally {
+ removeNativeCache(cacheName);
+ }
+ }
+
+ @Test
+ public void getOnUnknownCache() {
+ T cacheManager = getCacheManager(false);
+ String cacheName = name.getMethodName();
+ assertFalse(cacheManager.getCacheNames().contains(cacheName));
+ assertThat(cacheManager.getCache(cacheName), nullValue());
+ }
+
+ @Test
+ public void getTransactionalOnExistingCache() {
+ assertThat(getCacheManager(true).getCache(CACHE_NAME),
+ is(instanceOf(TransactionAwareCacheDecorator.class)));
+ }
+
+ @Test
+ public void getTransactionalOnNewCache() {
+ String cacheName = name.getMethodName();
+ T cacheManager = getCacheManager(true);
+ assertFalse(cacheManager.getCacheNames().contains(cacheName));
+ addNativeCache(cacheName);
+ try {
+ assertThat(cacheManager.getCache(cacheName),
+ is(instanceOf(TransactionAwareCacheDecorator.class)));
+ assertTrue(cacheManager.getCacheNames().contains(cacheName));
+ } finally {
+ removeNativeCache(cacheName);
+ }
+ }
+}
diff --git a/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java b/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java
index 364472409b..677f7fe3ac 100644
--- a/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java
+++ b/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.springframework.cache.CacheManager;
*
* @author Costin Leau
* @author Juergen Hoeller
+ * @author Stephane Nicoll
* @since 3.1
*/
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
@@ -70,10 +71,36 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
return cache;
}
+ /**
+ * Return a missing cache with the specified {@code name} or {@code null} if
+ * such cache does not exist or could not be created on the fly.
+ * Some caches may be created at runtime in the native provided. If a lookup
+ * by name does not yield any result, a subclass gets a chance to register
+ * such a cache at runtime. The returned cache will be automatically added to
+ * this instance.
+ * @param name the name of the cache to retrieve
+ * @return the missing cache or {@code null} if no such cache exists or could be
+ * created
+ * @see #getCache(String)
+ */
+ protected Cache getMissingCache(String name) {
+ return null;
+ }
@Override
public Cache getCache(String name) {
- return this.cacheMap.get(name);
+ Cache cache = lookupCache(name);
+ if (cache != null) {
+ return cache;
+ }
+ else {
+ Cache missingCache = getMissingCache(name);
+ if (missingCache != null) {
+ addCache(missingCache);
+ return lookupCache(name); // May be decorated
+ }
+ return null;
+ }
}
@Override
@@ -81,6 +108,9 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
return Collections.unmodifiableSet(this.cacheNames);
}
+ private Cache lookupCache(String name) {
+ return this.cacheMap.get(name);
+ }
/**
* Load the caches for this cache manager. Occurs at startup.