diff --git a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj index 61f2551931f..923324ceb39 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj @@ -22,7 +22,7 @@ import java.util.concurrent.Callable; import org.aspectj.lang.annotation.SuppressAjWarnings; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.cache.interceptor.CacheAspectSupport; -import org.springframework.cache.interceptor.CacheDefinitionSource; +import org.springframework.cache.interceptor.CacheOperationSource; /** * Abstract superaspect for AspectJ cache aspects. Concrete @@ -46,11 +46,11 @@ public abstract aspect AbstractCacheAspect extends CacheAspectSupport { /** * Construct object using the given caching metadata retrieval strategy. - * @param cds {@link CacheDefinitionSource} implementation, retrieving Spring + * @param cos {@link CacheOperationSource} implementation, retrieving Spring * cache metadata for each joinpoint. */ - protected AbstractCacheAspect(CacheDefinitionSource... cds) { - setCacheDefinitionSources(cds); + protected AbstractCacheAspect(CacheOperationSource... cos) { + setCacheDefinitionSources(cos); } @SuppressAjWarnings("adviceDidNotMatch") @@ -75,7 +75,7 @@ public abstract aspect AbstractCacheAspect extends CacheAspectSupport { /** * Concrete subaspects must implement this pointcut, to identify * cached methods. For each selected joinpoint, {@link CacheOperationDefinition} - * will be retrieved using Spring's {@link CacheDefinitionSource} interface. + * will be retrieved using Spring's {@link CacheOperationSource} interface. */ protected abstract pointcut cacheMethodExecution(Object cachedObject); } \ No newline at end of file diff --git a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj index 3ef92e640a1..4cb3fe1192c 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj @@ -16,7 +16,7 @@ package org.springframework.cache.aspectj; -import org.springframework.cache.annotation.AnnotationCacheDefinitionSource; +import org.springframework.cache.annotation.AnnotationCacheOperationSource; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; @@ -43,7 +43,7 @@ import org.springframework.cache.annotation.Cacheable; public aspect AnnotationCacheAspect extends AbstractCacheAspect { public AnnotationCacheAspect() { - super(new AnnotationCacheDefinitionSource(false)); + super(new AnnotationCacheOperationSource(false)); } /** diff --git a/org.springframework.context/src/main/java/org/springframework/cache/Cache.java b/org.springframework.context/src/main/java/org/springframework/cache/Cache.java index c560f1dd15c..aab14aa7ad6 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/Cache.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/Cache.java @@ -28,6 +28,18 @@ package org.springframework.cache; */ public interface Cache { + /** + * A (wrapper) object representing a cache value. + */ + interface ValueWrapper { + /** + * Returns the actual value in the cache. + * + * @return cache value + */ + V get(); + } + /** * Returns the cache name. * @@ -38,164 +50,36 @@ public interface Cache { /** * Returns the the native, underlying cache provider. * - * @return + * @return the underlying native cache provider. */ Object getNativeCache(); /** - * Returns true if this cache contains a mapping for the specified - * key. More formally, returns true if and only if - * this cache contains a mapping for a key k such that - * (key==null ? k==null : key.equals(k)). (There can be - * at most one such mapping.) - * - * @param key key whose presence in this cache is to be tested. - * @return true if this cache contains a mapping for the specified - * key. - */ - boolean containsKey(Object key); - - /** - * Returns the value to which this cache maps the specified key. Returns - * null if the cache contains no mapping for this key. A return - * value of null does not necessarily indicate that the - * cache contains no mapping for the key; it's also possible that the cache - * explicitly maps the key to null. The containsKey - * operation may be used to distinguish these two cases. - * - *

More formally, if this cache contains a mapping from a key - * k to a value v such that (key==null ? k==null : - * key.equals(k)), then this method returns v; otherwise - * it returns null. (There can be at most one such mapping.) - * + * Returns the value to which this cache maps the specified key. Returns + * null if the cache contains no mapping for this key. + * * @param key key whose associated value is to be returned. * @return the value to which this cache maps the specified key, or * null if the cache contains no mapping for this key. - * - * @see #containsKey(Object) */ - V get(Object key); - + ValueWrapper get(Object key); /** - * Associates the specified value with the specified key in this cache - * (optional operation). If the cache previously contained a mapping for - * this key, the old value is replaced by the specified value. (A cache - * m is said to contain a mapping for a key k if and only - * if {@link #containsKey(Object) m.containsKey(k)} would return - * true.)) + * Associates the specified value with the specified key in this cache. + * If the cache previously contained a mapping for this key, the old + * value is replaced by the specified value. * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the cache previously associated null - * with the specified key, if the implementation supports - * null values. */ - V put(K key, V value); - + void put(K key, V value); /** - * If the specified key is not already associated with a value, associate it with the given value. - * - * This is equivalent to: - *

-	 *  if (!cache.containsKey(key)) 
-	 *     return cache.put(key, value);
-	 *  else
-	 *     return cache.get(key);
-	 *	
- * - * @param key key with which the specified value is to be associated. - * @param value value to be associated with the specified key. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the cache previously associated null - * with the specified key, if the implementation supports - * null values. - */ - V putIfAbsent(K key, V value); - - - /** - * Removes the mapping for this key from this cache if it is present - * (optional operation). More formally, if this cache contains a mapping - * from key k to value v such that - * (key==null ? k==null : key.equals(k)), that mapping - * is removed. (The cache can contain at most one such mapping.) - * - *

Returns the value to which the cache previously associated the key, or - * null if the cache contained no mapping for this key. (A - * null return can also indicate that the cache previously - * associated null with the specified key if the implementation - * supports null values.) The cache will not contain a mapping for - * the specified key once the call returns. + * Evicts the mapping for this key from this cache if it is present. * * @param key key whose mapping is to be removed from the cache. - * @return previous value associated with specified key, or null - * if there was no mapping for key. */ - V remove(Object key); - - - /** - * Remove entry for key only if currently mapped to given value. - * - * Similar to: - *

-	 *   if ((cache.containsKey(key) && cache.get(key).equals(value)) {
-	 *      cache.remove(key);
-	 *      return true;
-	 *   } 
-	 *   else 
-	 *      return false;
-	 * 
- * - * @param key key with which the specified value is associated. - * @param value value associated with the specified key. - * @return true if the value was removed, false otherwise - */ - boolean remove(Object key, Object value); - - - /** - * Replace entry for key only if currently mapped to given value. - * - * Similar to: - *
 
-	 *  if ((cache.containsKey(key) && cache.get(key).equals(oldValue)) {
-	 *     cache.put(key, newValue);
-	 *     return true;
-	 * } else return false;
-	 * 
- - * @param key key with which the specified value is associated. - * @param oldValue value expected to be associated with the specified key. - * @param newValue value to be associated with the specified key. - * @return true if the value was replaced - */ - boolean replace(K key, V oldValue, V newValue); - - /** - * Replace entry for key only if currently mapped to some value. - * Acts as - *
 
-	 *  if ((cache.containsKey(key)) {
-	 *     return cache.put(key, value);
-	 * } else return null;
-	 * 
- * except that the action is performed atomically. - * @param key key with which the specified value is associated. - * @param value value to be associated with the specified key. - * @return previous value associated with specified key, or null - * if there was no mapping for key. A null return can - * also indicate that the cache previously associated null - * with the specified key, if the implementation supports - * null values. - */ - V replace(K key, V value); - + void evict(Object key); /** * Removes all mappings from the cache. diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheDefinitionSource.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheDefinitionSource.java deleted file mode 100644 index c463cac8913..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheDefinitionSource.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2010-2011 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.annotation; - -import java.io.Serializable; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.cache.interceptor.AbstractFallbackCacheDefinitionSource; -import org.springframework.cache.interceptor.CacheDefinition; -import org.springframework.util.Assert; - -/** - * - * Implementation of the - * {@link org.springframework.cache.interceptor.CacheDefinitionSource} - * interface for working with caching metadata in JDK 1.5+ annotation format. - * - *

This class reads Spring's JDK 1.5+ {@link Cacheable} and {@link CacheEvict} - * annotations and - * exposes corresponding caching operation definition to Spring's cache infrastructure. - * This class may also serve as base class for a custom CacheDefinitionSource. - * - * @author Costin Leau - */ -@SuppressWarnings("serial") -public class AnnotationCacheDefinitionSource extends AbstractFallbackCacheDefinitionSource implements - Serializable { - - private final boolean publicMethodsOnly; - - private final Set annotationParsers; - - /** - * Create a default AnnotationCacheOperationDefinitionSource, supporting - * public methods that carry the Cacheable and CacheInvalidate - * annotations. - */ - public AnnotationCacheDefinitionSource() { - this(true); - } - - /** - * Create a custom AnnotationCacheOperationDefinitionSource, supporting - * public methods that carry the Cacheable and - * CacheInvalidate annotations. - * - * @param publicMethodsOnly whether to support only annotated public methods - * typically for use with proxy-based AOP), or protected/private methods as well - * (typically used with AspectJ class weaving) - */ - public AnnotationCacheDefinitionSource(boolean publicMethodsOnly) { - this.publicMethodsOnly = publicMethodsOnly; - this.annotationParsers = new LinkedHashSet(1); - this.annotationParsers.add(new SpringCachingAnnotationParser()); - } - - /** - * Create a custom AnnotationCacheOperationDefinitionSource. - * @param annotationParsers the CacheAnnotationParser to use - */ - public AnnotationCacheDefinitionSource(CacheAnnotationParser... annotationParsers) { - this.publicMethodsOnly = true; - Assert.notEmpty(annotationParsers, "At least one CacheAnnotationParser needs to be specified"); - Set parsers = new LinkedHashSet(annotationParsers.length); - Collections.addAll(parsers, annotationParsers); - this.annotationParsers = parsers; - } - - @Override - protected CacheDefinition findCacheDefinition(Class clazz) { - return determineCacheDefinition(clazz); - } - - @Override - protected CacheDefinition findCacheOperation(Method method) { - return determineCacheDefinition(method); - } - - /** - * Determine the cache operation definition for the given method or class. - *

This implementation delegates to configured - * {@link CacheAnnotationParser CacheAnnotationParsers} - * for parsing known annotations into Spring's metadata attribute class. - * Returns null if it's not cacheable. - *

Can be overridden to support custom annotations that carry caching metadata. - * @param ae the annotated method or class - * @return CacheOperationDefinition the configured caching operation, - * or null if none was found - */ - protected CacheDefinition determineCacheDefinition(AnnotatedElement ae) { - for (CacheAnnotationParser annotationParser : this.annotationParsers) { - CacheDefinition attr = annotationParser.parseCacheAnnotation(ae); - if (attr != null) { - return attr; - } - } - return null; - } - - /** - * By default, only public methods can be made cacheable. - */ - @Override - protected boolean allowPublicMethodsOnly() { - return this.publicMethodsOnly; - } -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java index cfb474831e1..aab6ce72554 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java @@ -18,7 +18,7 @@ package org.springframework.cache.annotation; import java.lang.reflect.AnnotatedElement; -import org.springframework.cache.interceptor.CacheDefinition; +import org.springframework.cache.interceptor.CacheOperation; /** @@ -38,9 +38,9 @@ public interface CacheAnnotationParser { * metadata attribute class. Returns null if the method/class * is not cacheable. * @param ae the annotated method or class - * @return CacheOperationDefinition the configured caching operation, + * @return CacheOperation the configured caching operation, * or null if none was found - * @see AnnotationCacheDefinitionSource#determineCacheOperationDefinition + * @see AnnotationCacheOperationSource#determineCacheOperation */ - CacheDefinition parseCacheAnnotation(AnnotatedElement ae); + CacheOperation parseCacheAnnotation(AnnotatedElement ae); } diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCachingAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCachingAnnotationParser.java index 7c15ca30bab..8a5eef1d0d6 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCachingAnnotationParser.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCachingAnnotationParser.java @@ -20,11 +20,9 @@ import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import org.springframework.cache.interceptor.CacheDefinition; -import org.springframework.cache.interceptor.CacheInvalidateDefinition; -import org.springframework.cache.interceptor.CacheUpdateDefinition; -import org.springframework.cache.interceptor.DefaultCacheInvalidateDefinition; -import org.springframework.cache.interceptor.DefaultCacheUpdateDefinition; +import org.springframework.cache.interceptor.CacheEvictOperation; +import org.springframework.cache.interceptor.CacheOperation; +import org.springframework.cache.interceptor.CacheUpdateOperation; /** * Strategy implementation for parsing Spring's {@link Cacheable} and {@link CacheEvict} annotations. @@ -34,7 +32,7 @@ import org.springframework.cache.interceptor.DefaultCacheUpdateDefinition; @SuppressWarnings("serial") public class SpringCachingAnnotationParser implements CacheAnnotationParser, Serializable { - public CacheDefinition parseCacheAnnotation(AnnotatedElement ae) { + public CacheOperation parseCacheAnnotation(AnnotatedElement ae) { Cacheable update = findAnnotation(ae, Cacheable.class); if (update != null) { @@ -44,7 +42,7 @@ public class SpringCachingAnnotationParser implements CacheAnnotationParser, Ser CacheEvict invalidate = findAnnotation(ae, CacheEvict.class); if (invalidate != null) { - return parseInvalidateAnnotation(ae, invalidate); + return parseEvictAnnotation(ae, invalidate); } return null; @@ -63,8 +61,8 @@ public class SpringCachingAnnotationParser implements CacheAnnotationParser, Ser return ann; } - CacheUpdateDefinition parseCacheableAnnotation(AnnotatedElement target, Cacheable ann) { - DefaultCacheUpdateDefinition dcud = new DefaultCacheUpdateDefinition(); + CacheUpdateOperation parseCacheableAnnotation(AnnotatedElement target, Cacheable ann) { + CacheUpdateOperation dcud = new CacheUpdateOperation(); dcud.setCacheNames(ann.value()); dcud.setCondition(ann.condition()); dcud.setKey(ann.key()); @@ -73,8 +71,8 @@ public class SpringCachingAnnotationParser implements CacheAnnotationParser, Ser return dcud; } - CacheInvalidateDefinition parseInvalidateAnnotation(AnnotatedElement target, CacheEvict ann) { - DefaultCacheInvalidateDefinition dcid = new DefaultCacheInvalidateDefinition(); + CacheEvictOperation parseEvictAnnotation(AnnotatedElement target, CacheEvict ann) { + CacheEvictOperation dcid = new CacheEvictOperation(); dcid.setCacheNames(ann.value()); dcid.setCondition(ann.condition()); dcid.setKey(ann.key()); diff --git a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentCache.java b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentCache.java index 612216719a4..13cdc057122 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentCache.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentCache.java @@ -54,52 +54,4 @@ public class ConcurrentCache extends AbstractDelegatingCache { public ConcurrentMap getNativeCache() { return store; } - - @SuppressWarnings("unchecked") - public V putIfAbsent(K key, V value) { - if (getAllowNullValues()) { - if (value == null) { - ConcurrentMap raw = store; - return filterNull((V) raw.putIfAbsent(key, NULL_HOLDER)); - } - } - return filterNull(store.putIfAbsent(key, value)); - } - - @SuppressWarnings("unchecked") - public boolean remove(Object key, Object value) { - if (getAllowNullValues()) { - if (value == null) { - ConcurrentMap raw = store; - return raw.remove(key, NULL_HOLDER); - } - } - - return store.remove(key, value); - } - - @SuppressWarnings("unchecked") - public boolean replace(K key, V oldValue, V newValue) { - if (getAllowNullValues()) { - Object rawOldValue = (oldValue == null ? NULL_HOLDER : oldValue); - Object rawNewValue = (newValue == null ? NULL_HOLDER : newValue); - - ConcurrentMap raw = store; - return raw.replace(key, rawOldValue, rawNewValue); - } - - return store.replace(key, oldValue, newValue); - } - - @SuppressWarnings("unchecked") - public V replace(K key, V value) { - if (getAllowNullValues()) { - if (value == null) { - ConcurrentMap raw = store; - return filterNull((V) raw.replace(key, NULL_HOLDER)); - } - } - - return filterNull(store.replace(key, value)); - } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java b/org.springframework.context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java index 098f56962c5..2b49436670d 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java @@ -16,9 +16,7 @@ package org.springframework.cache.config; -import static org.springframework.context.annotation.AnnotationConfigUtils.CACHE_ADVISOR_BEAN_NAME; -import static org.springframework.context.annotation.AnnotationConfigUtils.CACHE_ASPECT_BEAN_NAME; -import static org.springframework.context.annotation.AnnotationConfigUtils.CACHE_ASPECT_CLASS_NAME; +import static org.springframework.context.annotation.AnnotationConfigUtils.*; import org.springframework.aop.config.AopNamespaceUtils; import org.springframework.beans.factory.config.BeanDefinition; @@ -28,8 +26,8 @@ import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.cache.annotation.AnnotationCacheDefinitionSource; -import org.springframework.cache.interceptor.BeanFactoryCacheDefinitionSourceAdvisor; +import org.springframework.cache.annotation.AnnotationCacheOperationSource; +import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor; import org.springframework.cache.interceptor.CacheInterceptor; import org.w3c.dom.Element; @@ -114,7 +112,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser Object eleSource = parserContext.extractSource(element); // Create the CacheDefinitionSource definition. - RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheDefinitionSource.class); + RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class); sourceDef.setSource(eleSource); sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef); @@ -128,7 +126,7 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); // Create the CacheAdvisor definition. - RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheDefinitionSourceAdvisor.class); + RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class); advisorDef.setSource(eleSource); advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); advisorDef.getPropertyValues().add("cacheDefinitionSource", new RuntimeBeanReference(sourceName)); diff --git a/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java b/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java index 995bb6bcbac..567d500037d 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCache.java @@ -21,6 +21,7 @@ import net.sf.ehcache.Element; import net.sf.ehcache.Status; import org.springframework.cache.Cache; +import org.springframework.cache.interceptor.DefaultValue; import org.springframework.util.Assert; /** @@ -57,77 +58,16 @@ public class EhCacheCache implements Cache { cache.removeAll(); } - public boolean containsKey(Object key) { - // get the element to force the expiry check (since #isKeyInCache does not considers that) - Element element = cache.getQuiet(key); - return (element != null ? true : false); - } - - public Object get(Object key) { + public ValueWrapper get(Object key) { Element element = cache.get(key); - return (element != null ? element.getObjectValue() : null); + return (element != null ? new DefaultValue(element.getObjectValue()) : null); } - public Object put(Object key, Object value) { - Element previous = cache.getQuiet(key); + public void put(Object key, Object value) { cache.put(new Element(key, value)); - return (previous != null ? previous.getValue() : null); } - public Object remove(Object key) { - Element element = cache.getQuiet(key); - Object value = (element != null ? element.getObjectValue() : null); + public void evict(Object key) { cache.remove(key); - return value; - } - - public Object putIfAbsent(Object key, Object value) { - // putIfAbsent supported only from Ehcache 2.1 - // return cache.putIfAbsent(new Element(key, value)); - Element existing = cache.getQuiet(key); - if (existing == null) { - cache.put(new Element(key, value)); - return null; - } - return existing.getObjectValue(); - } - - public boolean remove(Object key, Object value) { - // remove(Element) supported only from Ehcache 2.1 - // return cache.removeElement(new Element(key, value)); - Element existing = cache.getQuiet(key); - - if (existing != null && existing.getObjectValue().equals(value)) { - cache.remove(key); - return true; - } - - return false; - } - - public Object replace(Object key, Object value) { - // replace(Object, Object) supported only from Ehcache 2.1 - // return cache.replace(new Element(key, value)); - Element existing = cache.getQuiet(key); - - if (existing != null) { - cache.put(new Element(key, value)); - return existing.getObjectValue(); - } - - return null; - } - - public boolean replace(Object key, Object oldValue, Object newValue) { - // replace(Object, Object, Object) supported only from Ehcache 2.1 - // return cache.replace(new Element(key, oldValue), new Element(key, - // newValue)); - Element existing = cache.getQuiet(key); - - if (existing != null && existing.getObjectValue().equals(oldValue)) { - cache.put(new Element(key, newValue)); - return true; - } - return false; } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractCacheDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractCacheDefinition.java deleted file mode 100644 index a437d1a9b17..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractCacheDefinition.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.util.Assert; - -/** - * Base class implementing {@link CacheDefinition}. - * - * @author Costin Leau - */ -abstract class AbstractCacheDefinition implements CacheDefinition { - - private Set cacheNames = Collections.emptySet(); - private String condition = ""; - private String key = ""; - private String name = ""; - - - public Set getCacheNames() { - return cacheNames; - } - - public String getCondition() { - return condition; - } - - public String getKey() { - return key; - } - - public String getName() { - return name; - } - - public void setCacheName(String cacheName) { - Assert.hasText(cacheName); - this.cacheNames = Collections.singleton(cacheName); - } - - public void setCacheNames(String[] cacheNames) { - Assert.notEmpty(cacheNames); - this.cacheNames = new LinkedHashSet(cacheNames.length); - for (String string : cacheNames) { - this.cacheNames.add(string); - } - } - - public void setCondition(String condition) { - Assert.notNull(condition); - this.condition = condition; - } - - public void setKey(String key) { - Assert.notNull(key); - this.key = key; - } - - public void setName(String name) { - Assert.hasText(name); - this.name = name; - } - - /** - * This implementation compares the toString() results. - * @see #toString() - */ - @Override - public boolean equals(Object other) { - return (other instanceof CacheDefinition && toString().equals(other.toString())); - } - - /** - * This implementation returns toString()'s hash code. - * @see #toString() - */ - @Override - public int hashCode() { - return toString().hashCode(); - } - - /** - * Return an identifying description for this cache operation definition. - *

Has to be overridden in subclasses for correct equals - * and hashCode behavior. Alternatively, {@link #equals} - * and {@link #hashCode} can be overridden themselves. - */ - @Override - public String toString() { - return getDefinitionDescription().toString(); - } - - /** - * Return an identifying description for this caching definition. - *

Available to subclasses, for inclusion in their toString() result. - */ - protected StringBuilder getDefinitionDescription() { - StringBuilder result = new StringBuilder(); - result.append("CacheDefinition["); - result.append(name); - result.append("] caches="); - result.append(cacheNames); - result.append(" | condition='"); - result.append(condition); - result.append("' | key='"); - result.append(key); - result.append("'"); - return result; - } -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheDefinitionSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheDefinitionSource.java deleted file mode 100644 index c1276b733c2..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheDefinitionSource.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.BridgeMethodResolver; -import org.springframework.util.ClassUtils; -import org.springframework.util.ObjectUtils; - -/** - * Abstract implementation of {@link CacheDefinition} that caches - * attributes for methods and implements a fallback policy: 1. specific target - * method; 2. target class; 3. declaring method; 4. declaring class/interface. - * - *

Defaults to using the target class's caching attribute if none is - * associated with the target method. Any caching attribute associated with - * the target method completely overrides a class caching attribute. - * If none found on the target class, the interface that the invoked method - * has been called through (in case of a JDK proxy) will be checked. - * - *

This implementation caches attributes by method after they are first used. - * If it is ever desirable to allow dynamic changing of cacheable attributes - * (which is very unlikely), caching could be made configurable. - - * @author Costin Leau - * @see org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource - */ -public abstract class AbstractFallbackCacheDefinitionSource implements CacheDefinitionSource { - - /** - * Canonical value held in cache to indicate no caching attribute was - * found for this method, and we don't need to look again. - */ - private final static CacheDefinition NULL_CACHING_ATTRIBUTE = new DefaultCacheUpdateDefinition(); - - /** - * Logger available to subclasses. - *

As this base class is not marked Serializable, the logger will be recreated - * after serialization - provided that the concrete subclass is Serializable. - */ - protected final Log logger = LogFactory.getLog(getClass()); - - /** - * Cache of CacheOperationDefinitions, keyed by DefaultCacheKey (Method + target Class). - *

As this base class is not marked Serializable, the cache will be recreated - * after serialization - provided that the concrete subclass is Serializable. - */ - final Map attributeCache = new ConcurrentHashMap(); - - /** - * Determine the caching attribute for this method invocation. - *

Defaults to the class's caching attribute if no method attribute is found. - * @param method the method for the current invocation (never null) - * @param targetClass the target class for this invocation (may be null) - * @return {@link CacheDefinition} for this method, or null if the method - * is not cacheable - */ - public CacheDefinition getCacheDefinition(Method method, Class targetClass) { - // First, see if we have a cached value. - Object cacheKey = getCacheKey(method, targetClass); - CacheDefinition cached = this.attributeCache.get(cacheKey); - if (cached != null) { - if (cached == NULL_CACHING_ATTRIBUTE) { - return null; - } - // Value will either be canonical value indicating there is no caching attribute, - // or an actual caching attribute. - return cached; - } - else { - // We need to work it out. - CacheDefinition cacheDef = computeCacheOperationDefinition(method, targetClass); - // Put it in the cache. - if (cacheDef == null) { - this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE); - } - else { - if (logger.isDebugEnabled()) { - logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheDef); - } - this.attributeCache.put(cacheKey, cacheDef); - } - return cacheDef; - } - } - - /** - * Determine a cache key for the given method and target class. - *

Must not produce same key for overloaded methods. - * Must produce same key for different instances of the same method. - * @param method the method (never null) - * @param targetClass the target class (may be null) - * @return the cache key (never null) - */ - protected Object getCacheKey(Method method, Class targetClass) { - return new DefaultCacheKey(method, targetClass); - } - - /** - * Same signature as {@link #getTransactionAttribute}, but doesn't cache the result. - * {@link #getTransactionAttribute} is effectively a caching decorator for this method. - * @see #getTransactionAttribute - */ - private CacheDefinition computeCacheOperationDefinition(Method method, Class targetClass) { - // Don't allow no-public methods as required. - if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { - return null; - } - - // The method may be on an interface, but we need attributes from the target class. - // If the target class is null, the method will be unchanged. - Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); - // If we are dealing with method with generic parameters, find the original method. - specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); - - // First try is the method in the target class. - CacheDefinition opDef = findCacheOperation(specificMethod); - if (opDef != null) { - return opDef; - } - - // Second try is the caching operation on the target class. - opDef = findCacheDefinition(specificMethod.getDeclaringClass()); - if (opDef != null) { - return opDef; - } - - if (specificMethod != method) { - // Fall back is to look at the original method. - opDef = findCacheOperation(method); - if (opDef != null) { - return opDef; - } - // Last fall back is the class of the original method. - return findCacheDefinition(method.getDeclaringClass()); - } - return null; - } - - /** - * Subclasses need to implement this to return the caching attribute - * for the given method, if any. - * @param method the method to retrieve the attribute for - * @return all caching attribute associated with this method - * (or null if none) - */ - protected abstract CacheDefinition findCacheOperation(Method method); - - /** - * Subclasses need to implement this to return the caching attribute - * for the given class, if any. - * @param clazz the class to retrieve the attribute for - * @return all caching attribute associated with this class - * (or null if none) - */ - protected abstract CacheDefinition findCacheDefinition(Class clazz); - - /** - * Should only public methods be allowed to have caching semantics? - *

The default implementation returns false. - */ - protected boolean allowPublicMethodsOnly() { - return false; - } - - /** - * Default cache key for the CacheOperationDefinition cache. - */ - private static class DefaultCacheKey { - - private final Method method; - - private final Class targetClass; - - public DefaultCacheKey(Method method, Class targetClass) { - this.method = method; - this.targetClass = targetClass; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof DefaultCacheKey)) { - return false; - } - DefaultCacheKey otherKey = (DefaultCacheKey) other; - return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(this.targetClass, - otherKey.targetClass)); - } - - @Override - public int hashCode() { - return this.method.hashCode() * 29 + (this.targetClass != null ? this.targetClass.hashCode() : 0); - } - } -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheDefinitionSourceAdvisor.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheDefinitionSourceAdvisor.java deleted file mode 100644 index 7e296e63f59..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheDefinitionSourceAdvisor.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import org.springframework.aop.ClassFilter; -import org.springframework.aop.Pointcut; -import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor; - -/** - * Advisor driven by a {@link CacheDefinitionSource}, used to include a - * transaction advice bean for methods that are transactional. - * - * @author Costin Leau - */ -@SuppressWarnings("serial") -public class BeanFactoryCacheDefinitionSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { - - private CacheDefinitionSource cacheDefinitionSource; - - private final CacheDefinitionSourcePointcut pointcut = new CacheDefinitionSourcePointcut() { - @Override - protected CacheDefinitionSource getCacheDefinitionSource() { - return cacheDefinitionSource; - } - }; - - /** - * Set the cache operation attribute source which is used to find cache - * attributes. This should usually be identical to the source reference - * set on the cache interceptor itself. - * @see CacheInterceptor#setCacheAttributeSource - */ - public void setCacheDefinitionSource(CacheDefinitionSource cacheDefinitionSource) { - this.cacheDefinitionSource = cacheDefinitionSource; - } - - /** - * Set the {@link ClassFilter} to use for this pointcut. - * Default is {@link ClassFilter#TRUE}. - */ - public void setClassFilter(ClassFilter classFilter) { - this.pointcut.setClassFilter(classFilter); - } - - public Pointcut getPointcut() { - return this.pointcut; - } -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java index 5a209f95024..7b59f5e83df 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java @@ -64,7 +64,7 @@ public abstract class CacheAspectSupport implements InitializingBean { private CacheManager cacheManager; - private CacheDefinitionSource cacheDefinitionSource; + private CacheOperationSource cacheDefinitionSource; private final ExpressionEvaluator evaluator = new ExpressionEvaluator(); @@ -102,7 +102,7 @@ public abstract class CacheAspectSupport implements InitializingBean { this.cacheManager = cacheManager; } - public CacheDefinitionSource getCacheDefinitionSource() { + public CacheOperationSource getCacheDefinitionSource() { return cacheDefinitionSource; } @@ -118,21 +118,21 @@ public abstract class CacheAspectSupport implements InitializingBean { * Set multiple cache definition sources which are used to find the cache * attributes. Will build a CompositeCachingDefinitionSource for the given sources. */ - public void setCacheDefinitionSources(CacheDefinitionSource... cacheDefinitionSources) { + public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) { Assert.notEmpty(cacheDefinitionSources); - this.cacheDefinitionSource = (cacheDefinitionSources.length > 1 ? new CompositeCacheDefinitionSource( + this.cacheDefinitionSource = (cacheDefinitionSources.length > 1 ? new CompositeCacheOperationSource( cacheDefinitionSources) : cacheDefinitionSources[0]); } - protected Collection> getCaches(CacheDefinition definition) { - Set cacheNames = definition.getCacheNames(); + protected Collection> getCaches(CacheOperation operation) { + Set cacheNames = operation.getCacheNames(); Collection> caches = new ArrayList>(cacheNames.size()); for (String cacheName : cacheNames) { Cache cache = cacheManager.getCache(cacheName); if (cache == null) { - throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + definition); + throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation); } caches.add(cache); } @@ -140,9 +140,9 @@ public abstract class CacheAspectSupport implements InitializingBean { return caches; } - protected CacheOperationContext getOperationContext(CacheDefinition definition, Method method, Object[] args, + protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args, Object target, Class targetClass) { - return new CacheOperationContext(definition, method, args, target, targetClass); + return new CacheOperationContext(operation, method, args, target, targetClass); } @SuppressWarnings("unchecked") @@ -156,112 +156,63 @@ public abstract class CacheAspectSupport implements InitializingBean { boolean log = logger.isTraceEnabled(); - final CacheDefinition cacheDef = getCacheDefinitionSource().getCacheDefinition(method, targetClass); + final CacheOperation cacheOp = getCacheDefinitionSource().getCacheOperation(method, targetClass); Object retVal = null; // analyze caching information - if (cacheDef != null) { - CacheOperationContext context = getOperationContext(cacheDef, method, args, target, targetClass); + if (cacheOp != null) { + CacheOperationContext context = getOperationContext(cacheOp, method, args, target, targetClass); Collection> caches = context.getCaches(); if (context.hasConditionPassed()) { // check operation - if (cacheDef instanceof CacheUpdateDefinition) { + if (cacheOp instanceof CacheUpdateOperation) { Object key = context.generateKey(); if (log) { - logger.trace("Computed cache key " + key + " for definition " + cacheDef); + logger.trace("Computed cache key " + key + " for definition " + cacheOp); } if (key == null) { throw new IllegalArgumentException( "Null key returned for cache definition (maybe you are using named params on classes without debug info?) " - + cacheDef); + + cacheOp); } - // - // check usage of single cache - // very common case which allows for some optimization - // in exchange for code readability - // + // for each cache + boolean cacheHit = false; - if (caches.size() == 1) { - Cache cache = caches.iterator().next(); + for (Iterator> iterator = caches.iterator(); iterator.hasNext() && !cacheHit;) { + Cache cache = iterator.next(); + Cache.ValueWrapper value = cache.get(key); - // always get the value - retVal = cache.get(key); - // to avoid race-conditions of entries being removed between contains/get calls - if (cache.containsKey(key)) { - if (log) { - logger.trace("Key " + key + " found in cache, returning value " + retVal); - } - return retVal; - } else { - if (log) { - logger.trace("Key " + key + " NOT found in cache, invoking target method for caching " - + method); - } - - retVal = invocation.call(); - cache.put(key, retVal); + if (value != null) { + cacheHit = true; + retVal = value.get(); } } - // - // multi cache path - // - else { - // to avoid the contains/get race condition we can: - // a. get the value in advanced (aka 'eagerGet') - // b. double check 'contains' before and after get - // a implies more calls in total if more then 3 caches are used (n*2 calls) - // b uses less calls in total but is 1 call heavier for one cache (n+2 calls) - // -- - // for balance, a) is used for up to 3 caches, b for more then 4 - - boolean eagerGet = caches.size() <= 3; - - // for each cache - boolean cacheHit = false; - - for (Iterator> iterator = caches.iterator(); iterator.hasNext() && !cacheHit;) { - Cache cache = iterator.next(); - if (eagerGet) { - retVal = cache.get(key); - } - if (cache.containsKey(key)) { - if (eagerGet) { - cacheHit = true; - } else { - retVal = cache.get(key); - cacheHit = cache.containsKey(key); - } - } + if (!cacheHit) { + if (log) { + logger.trace("Key " + key + " NOT found in cache(s), invoking cached target method " + + method); } + retVal = invocation.call(); + } else { + if (log) { + logger.trace("Key " + key + " found in cache, returning value " + retVal); + } + } - if (!cacheHit) { - if (log) { - logger.trace("Key " + key + " NOT found in cache(s), invoking cached target method " - + method); - } - retVal = invocation.call(); - } - else { - if (log) { - logger.trace("Key " + key + " found in cache, returning value " + retVal); - } - } - - // update all caches (if needed) - for (Cache cache : caches) { - cache.putIfAbsent(key, retVal); - } + // update all caches + for (Cache cache : caches) { + cache.put(key, retVal); } } - if (cacheDef instanceof CacheInvalidateDefinition) { - CacheInvalidateDefinition invalidateDef = (CacheInvalidateDefinition) cacheDef; + if (cacheOp instanceof CacheEvictOperation) { + CacheEvictOperation evictOp = (CacheEvictOperation) cacheOp; retVal = invocation.call(); // for each cache @@ -270,10 +221,10 @@ public abstract class CacheAspectSupport implements InitializingBean { for (Cache cache : caches) { // flush the cache (ignore arguments) - if (invalidateDef.isCacheWide()) { + if (evictOp.isCacheWide()) { cache.clear(); if (log) { - logger.trace("Invalidating entire cache for definition " + cacheDef + " on method " + logger.trace("Invalidating entire cache for definition " + cacheOp + " on method " + method); } } else { @@ -282,19 +233,18 @@ public abstract class CacheAspectSupport implements InitializingBean { key = context.generateKey(); } if (log) { - logger.trace("Invalidating cache key " + key + " for definition " + cacheDef + logger.trace("Invalidating cache key " + key + " for definition " + cacheOp + " on method " + method); } - cache.remove(key); + cache.evict(key); } } } return retVal; - } - else { + } else { if (log) { - logger.trace("Cache condition failed on method " + method + " for definition " + cacheDef); + logger.trace("Cache condition failed on method " + method + " for definition " + cacheOp); } } } @@ -304,7 +254,7 @@ public abstract class CacheAspectSupport implements InitializingBean { protected class CacheOperationContext { - private CacheDefinition definition; + private CacheOperation operation; private final Collection> caches; private final Object target; private final Method method; @@ -315,10 +265,10 @@ public abstract class CacheAspectSupport implements InitializingBean { private final KeyGenerator keyGenerator = CacheAspectSupport.this.keyGenerator; - public CacheOperationContext(CacheDefinition operationDefinition, Method method, Object[] args, - Object target, Class targetClass) { - this.definition = operationDefinition; - this.caches = CacheAspectSupport.this.getCaches(definition); + public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target, + Class targetClass) { + this.operation = operation; + this.caches = CacheAspectSupport.this.getCaches(operation); this.target = target; this.method = method; this.args = args; @@ -329,12 +279,12 @@ public abstract class CacheAspectSupport implements InitializingBean { /** * Evaluates the definition condition. * - * @param definition + * @param operation * @return */ protected boolean hasConditionPassed() { - if (StringUtils.hasText(definition.getCondition())) { - return evaluator.condition(definition.getCondition(), method, evalContext); + if (StringUtils.hasText(operation.getCondition())) { + return evaluator.condition(operation.getCondition(), method, evalContext); } return true; } @@ -342,7 +292,7 @@ public abstract class CacheAspectSupport implements InitializingBean { /** * Computes the key for the given caching definition. * - * @param definition + * @param operation * @param method * method being invoked * @param objects @@ -350,8 +300,8 @@ public abstract class CacheAspectSupport implements InitializingBean { * @return generated key (null if none can be generated) */ protected Object generateKey() { - if (StringUtils.hasText(definition.getKey())) { - return evaluator.key(definition.getKey(), method, evalContext); + if (StringUtils.hasText(operation.getKey())) { + return evaluator.key(operation.getKey(), method, evalContext); } return keyGenerator.extract(target, method, args); diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinition.java deleted file mode 100644 index b1a802c9482..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinition.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import java.util.Set; - -/** - * Interface describing Spring-compliant caching operation. - * - * @author Costin Leau - */ -public interface CacheDefinition { - - /** - * Returns the name of this operation. Can be null. - * In case of Spring's declarative caching, the exposed name will be: - * fully qualified class name.method name. - * - * @return the operation name - */ - String getName(); - - /** - * Returns the names of the cache against which this operation is performed. - * - * @return names of the cache on which the operation is performed. - */ - Set getCacheNames(); - - /** - * Returns the SpEL expression conditioning the operation. - * - * @return operation condition (as SpEL expression). - */ - String getCondition(); - - /** - * Returns the SpEL expression identifying the cache key. - * - * @return - */ - String getKey(); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinitionSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinitionSource.java deleted file mode 100644 index 4ce65edfa95..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinitionSource.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import java.lang.reflect.Method; - - -/** - * Interface used by CacheInterceptor. Implementations know - * how to source cache operation attributes, whether from configuration, - * metadata attributes at source level, or anywhere else. - * - * @author Costin Leau - */ -public interface CacheDefinitionSource { - - /** - * Return the cache operation definition for this method. - * Return null if the method is not cacheable. - * @param method method - * @param targetClass target class. May be null, in which - * case the declaring class of the method must be used. - * @return {@link CacheDefinition} the matching cache operation definition, - * or null if none found - */ - CacheDefinition getCacheDefinition(Method method, Class targetClass); -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinitionSourcePointcut.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinitionSourcePointcut.java deleted file mode 100644 index fcf2a6524db..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheDefinitionSourcePointcut.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import org.springframework.aop.support.StaticMethodMatcherPointcut; -import org.springframework.util.ObjectUtils; - -/** - * Inner class that implements a Pointcut that matches if the underlying - * {@link CacheDefinitionSource} has an attribute for a given method. - * - * @author Costin Leau - */ -@SuppressWarnings("serial") -abstract class CacheDefinitionSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { - - public boolean matches(Method method, Class targetClass) { - CacheDefinitionSource cas = getCacheDefinitionSource(); - return (cas == null || cas.getCacheDefinition(method, targetClass) != null); - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof CacheDefinitionSourcePointcut)) { - return false; - } - CacheDefinitionSourcePointcut otherPc = (CacheDefinitionSourcePointcut) other; - return ObjectUtils.nullSafeEquals(getCacheDefinitionSource(), - otherPc.getCacheDefinitionSource()); - } - - @Override - public int hashCode() { - return CacheDefinitionSourcePointcut.class.hashCode(); - } - - @Override - public String toString() { - return getClass().getName() + ": " + getCacheDefinitionSource(); - } - - - /** - * Obtain the underlying CacheOperationDefinitionSource (may be null). - * To be implemented by subclasses. - */ - protected abstract CacheDefinitionSource getCacheDefinitionSource(); -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInvalidateDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInvalidateDefinition.java deleted file mode 100644 index 65f89a60e0c..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInvalidateDefinition.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - - -/** - * Interface describing a Spring cache invalidation. - * - * @author Costin Leau - */ -public interface CacheInvalidateDefinition extends CacheDefinition { - - /** - * Returns whether the operation affects the entire cache or not. - * - * @return whether the operation is cache wide or not. - */ - boolean isCacheWide(); -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java index ea6348389cf..2460c30d403 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheProxyFactoryBean.java @@ -49,7 +49,7 @@ public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean { * * @param cacheDefinitionSources cache definition sources */ - public void setCacheDefinitionSources(CacheDefinitionSource... cacheDefinitionSources) { + public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) { this.cachingInterceptor.setCacheDefinitionSources(cacheDefinitionSources); } diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateDefinition.java deleted file mode 100644 index 1461b9dbb03..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateDefinition.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -/** - * Interface describing a Spring cache update. - * - * @author Costin Leau - */ -public interface CacheUpdateDefinition extends CacheDefinition { - - /** - * Returns the SpEL expression identifying the cache key. - * - * @return - */ - String getKey(); -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheDefinitionSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheDefinitionSource.java deleted file mode 100644 index f0707d0a3a0..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheDefinitionSource.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import org.springframework.util.Assert; - -/** - * Composite {@link CacheDefinitionSource} implementation that iterates - * over a given array of {@link CacheDefinitionSource} instances. - * - * @author Costin Leau - */ -@SuppressWarnings("serial") -public class CompositeCacheDefinitionSource implements CacheDefinitionSource, Serializable { - - private final CacheDefinitionSource[] cacheDefinitionSources; - - /** - * Create a new CompositeCachingDefinitionSource for the given sources. - * @param cacheDefinitionSourcess the CacheDefinitionSource instances to combine - */ - public CompositeCacheDefinitionSource(CacheDefinitionSource[] cacheDefinitionSources) { - Assert.notNull(cacheDefinitionSources, "cacheDefinitionSource array must not be null"); - this.cacheDefinitionSources = cacheDefinitionSources; - } - - /** - * Return the CacheDefinitionSource instances that this - * CompositeCachingDefinitionSource combines. - */ - public final CacheDefinitionSource[] getCacheDefinitionSources() { - return this.cacheDefinitionSources; - } - - - public CacheDefinition getCacheDefinition(Method method, Class targetClass) { - for (CacheDefinitionSource source : cacheDefinitionSources) { - CacheDefinition definition = source.getCacheDefinition(method, targetClass); - if (definition != null) { - return definition; - } - } - - return null; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultCacheInvalidateDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultCacheInvalidateDefinition.java deleted file mode 100644 index 33aaf451396..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultCacheInvalidateDefinition.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -/** - * Default implementation of the {@link CacheInvalidateDefinition} interface. - * - * @author Costin Leau - */ -public class DefaultCacheInvalidateDefinition extends AbstractCacheDefinition implements - CacheInvalidateDefinition { - - private boolean cacheWide = false; - - public boolean isCacheWide() { - return cacheWide; - } - - public void setCacheWide(boolean cacheWide) { - this.cacheWide = cacheWide; - } - - @Override - protected StringBuilder getDefinitionDescription() { - StringBuilder sb = super.getDefinitionDescription(); - sb.append(","); - sb.append(cacheWide); - return sb; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultCacheUpdateDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultCacheUpdateDefinition.java deleted file mode 100644 index 57deeee4a02..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultCacheUpdateDefinition.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010-2011 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.interceptor; - -/** - * Default implementation of the {@link CacheUpdateDefinition} interface. - * - * @author Costin Leau - */ -public class DefaultCacheUpdateDefinition extends AbstractCacheDefinition implements CacheUpdateDefinition { - - -} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractDelegatingCache.java b/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractDelegatingCache.java index 448426b0556..f4bb5e209c5 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractDelegatingCache.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractDelegatingCache.java @@ -20,14 +20,16 @@ import java.io.Serializable; import java.util.Map; import org.springframework.cache.Cache; +import org.springframework.cache.interceptor.DefaultValue; import org.springframework.util.Assert; /** * Abstract base class delegating most of the {@link Map}-like methods * to the underlying cache. * - * Note:Allows null values to be stored, even if the underlying map - * does not support them. + * Note:Allows null values to be stored even (for cases where the + * underlying cache does not support them) as long as arbitrary serialized + * objects are supported. * * @author Costin Leau */ @@ -57,7 +59,7 @@ public abstract class AbstractDelegatingCache implements Cache { * * @param map type * @param delegate map delegate - * @param allowNullValues flag indicating whether null values are allowed or not + * @param allowNullValues flag indicating whether null values should be replaced or not */ public > AbstractDelegatingCache(D delegate, boolean allowNullValues) { Assert.notNull(delegate); @@ -73,30 +75,22 @@ public abstract class AbstractDelegatingCache implements Cache { delegate.clear(); } - public boolean containsKey(Object key) { - return delegate.containsKey(key); - } - - public V get(Object key) { - return filterNull(delegate.get(key)); + public ValueWrapper get(Object key) { + return new DefaultValue(filterNull(delegate.get(key))); } @SuppressWarnings("unchecked") - public V put(K key, V value) { + public void put(K key, V value) { if (allowNullValues && value == null) { Map map = delegate; - Object val = map.put(key, NULL_HOLDER); - if (val == NULL_HOLDER) { - return null; - } - return (V) val; + map.put(key, NULL_HOLDER); } - return filterNull(delegate.put(key, value)); + delegate.put(key, value); } - public V remove(Object key) { - return filterNull(delegate.remove(key)); + public void evict(Object key) { + delegate.remove(key); } protected V filterNull(V val) { diff --git a/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTest.java b/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTest.java index aaa231d93ed..220ddc2f04f 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTest.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTest.java @@ -54,11 +54,9 @@ public class EhCacheCacheTest extends AbstractNativeCacheTest { brancusi.setTimeToLive(3); nativeCache.put(brancusi); - assertTrue(cache.containsKey(key)); - assertEquals(value, cache.get(key)); + assertEquals(value, cache.get(key).get()); // wait for the entry to expire Thread.sleep(5 * 1000); - assertFalse("expired entry returned", cache.containsKey(key)); assertNull(cache.get(key)); } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTest.java b/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTest.java index 8d1da16968c..55abdf165be 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTest.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTest.java @@ -58,7 +58,6 @@ public abstract class AbstractNativeCacheTest { @Test public void testCachePut() throws Exception { - Object key = "enescu"; Object value = "george"; @@ -74,8 +73,6 @@ public abstract class AbstractNativeCacheTest { assertNull(cache.get(key)); cache.put(key, value); - assertEquals(value, cache.remove(key)); - assertNull(cache.get(key)); } @Test @@ -88,66 +85,4 @@ public abstract class AbstractNativeCacheTest { assertNull(cache.get("vlaicu")); assertNull(cache.get("enescu")); } - - // concurrent map tests - @Test - public void testPutIfAbsent() throws Exception { - Object key = "enescu"; - Object value1 = "george"; - Object value2 = "geo"; - - assertNull(cache.get("enescu")); - cache.put(key, value1); - cache.putIfAbsent(key, value2); - assertEquals(value1, cache.get(key)); - } - - @Test - public void testConcurrentRemove() throws Exception { - Object key = "enescu"; - Object value1 = "george"; - Object value2 = "geo"; - - assertNull(cache.get("enescu")); - cache.put(key, value1); - // no remove - cache.remove(key, value2); - assertEquals(value1, cache.get(key)); - // one remove - cache.remove(key, value1); - assertNull(cache.get("enescu")); - } - - @Test - public void testConcurrentReplace() throws Exception { - Object key = "enescu"; - Object value1 = "george"; - Object value2 = "geo"; - - assertNull(cache.get("enescu")); - cache.put(key, value1); - cache.replace(key, value2); - assertEquals(value2, cache.get(key)); - cache.remove(key); - cache.replace(key, value1); - assertNull(cache.get("enescu")); - } - - @Test - public void testConcurrentReplaceIfEqual() throws Exception { - Object key = "enescu"; - Object value1 = "george"; - Object value2 = "geo"; - - assertNull(cache.get("enescu")); - cache.put(key, value1); - assertEquals(value1, cache.get(key)); - // no replace - cache.replace(key, value2, value1); - assertEquals(value1, cache.get(key)); - cache.replace(key, value1, value2); - assertEquals(value2, cache.get(key)); - cache.replace(key, value2, value1); - assertEquals(value1, cache.get(key)); - } } \ No newline at end of file