Browse Source

Fix cache decoration

Prior to this commit, a cache that is added on-the-fly is not properly
decorated by the provided CacheManager implementation that supports
it (EhCache and JCache).

This commits adds an extra getMissingCache method to
the AbstractCacheManager that can be extended to provide a cache that
may exist in the native cache manager but is not yet known by the
spring abstraction.

Issue: SPR-11518
pull/461/merge
Stephane Nicoll 11 years ago
parent
commit
119dfd9cf9
  1. 18
      spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java
  2. 17
      spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java
  3. 79
      spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheManagerTests.java
  4. 106
      spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheCacheManagerTests.java
  5. 115
      spring-context-support/src/test/java/org/springframework/cache/transaction/AbstractTransactionSupportingCacheManagerTests.java
  6. 34
      spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java

18
spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java vendored

@ -31,6 +31,7 @@ import org.springframework.util.Assert; @@ -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 @@ -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;
}
}

17
spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java vendored

@ -31,6 +31,7 @@ import org.springframework.cache.transaction.AbstractTransactionSupportingCacheM @@ -31,6 +31,7 @@ import org.springframework.cache.transaction.AbstractTransactionSupportingCacheM
* <p>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 @@ -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<Object, Object> 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<Object, Object> jcache = getCacheManager().getCache(name);
if (jcache != null) {
return new JCacheCache(jcache, isAllowNullValues());
}
return cache;
return null;
}
}

79
spring-context-support/src/test/java/org/springframework/cache/ehcache/EhCacheCacheManagerTests.java vendored

@ -0,0 +1,79 @@ @@ -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<EhCacheCacheManager> {
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);
}
}

106
spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheCacheManagerTests.java vendored

@ -0,0 +1,106 @@ @@ -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<JCacheCacheManager> {
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<String> cacheNames;
private final CacheManager cacheManager;
private CacheManagerMock() {
this.cacheNames = new ArrayList<String>();
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);
}
}
}

115
spring-context-support/src/test/java/org/springframework/cache/transaction/AbstractTransactionSupportingCacheManagerTests.java vendored

@ -0,0 +1,115 @@ @@ -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<T extends CacheManager> {
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);
}
}
}

34
spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java vendored

@ -1,5 +1,5 @@ @@ -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; @@ -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 @@ -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.
* <p>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 @@ -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.

Loading…
Cancel
Save