From 3699a037a55ed4fbe43d66ecc73876f2378e3507 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Tue, 17 May 2011 16:58:15 +0000 Subject: [PATCH] revise cache API + add missing files (remember to check "show unversioned files") --- .../AnnotationCacheOperationSource.java | 123 ++++++++++ .../AbstractFallbackCacheOperationSource.java | 218 ++++++++++++++++++ ...eanFactoryCacheOperationSourceAdvisor.java | 62 +++++ .../interceptor/CacheEvictOperation.java | 43 ++++ .../cache/interceptor/CacheOperation.java | 128 ++++++++++ .../interceptor/CacheOperationSource.java | 41 ++++ .../CacheOperationSourcePointcut.java | 68 ++++++ .../interceptor/CacheUpdateOperation.java | 26 +++ .../CompositeCacheOperationSource.java | 63 +++++ .../cache/interceptor/DefaultValue.java | 37 +++ 10 files changed, 809 insertions(+) create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java create mode 100644 org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultValue.java diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java new file mode 100644 index 00000000000..a8ef94fbd31 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java @@ -0,0 +1,123 @@ +/* + * 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.AbstractFallbackCacheOperationSource; +import org.springframework.cache.interceptor.CacheOperation; +import org.springframework.util.Assert; + +/** + * + * Implementation of the {@link org.springframework.cache.interceptor.CacheOperationSource} + * 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 CacheOperationSource. + * + * @author Costin Leau + */ +@SuppressWarnings("serial") +public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements + Serializable { + + private final boolean publicMethodsOnly; + + private final Set annotationParsers; + + /** + * Create a default AnnotationCacheOperationSource, supporting + * public methods that carry the Cacheable and CacheEvict + * annotations. + */ + public AnnotationCacheOperationSource() { + this(true); + } + + /** + * Create a custom AnnotationCacheOperationSource, supporting + * public methods that carry the Cacheable and + * CacheEvict 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 AnnotationCacheOperationSource(boolean publicMethodsOnly) { + this.publicMethodsOnly = publicMethodsOnly; + this.annotationParsers = new LinkedHashSet(1); + this.annotationParsers.add(new SpringCachingAnnotationParser()); + } + + /** + * Create a custom AnnotationCacheOperationSource. + * @param annotationParsers the CacheAnnotationParser to use + */ + public AnnotationCacheOperationSource(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 CacheOperation findCacheOperation(Class clazz) { + return determineCacheOperation(clazz); + } + + @Override + protected CacheOperation findCacheOperation(Method method) { + return determineCacheOperation(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 CacheOperation the configured caching operation, + * or null if none was found + */ + protected CacheOperation determineCacheOperation(AnnotatedElement ae) { + for (CacheAnnotationParser annotationParser : this.annotationParsers) { + CacheOperation 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/interceptor/AbstractFallbackCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java new file mode 100644 index 00000000000..687ec82b635 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/AbstractFallbackCacheOperationSource.java @@ -0,0 +1,218 @@ +/* + * 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 CacheOperation} 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 AbstractFallbackCacheOperationSource implements CacheOperationSource { + + /** + * 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 CacheOperation NULL_CACHING_ATTRIBUTE = new CacheUpdateOperation(); + + /** + * 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 CacheOperation} for this method, or null if the method + * is not cacheable + */ + public CacheOperation getCacheOperation(Method method, Class targetClass) { + // First, see if we have a cached value. + Object cacheKey = getCacheKey(method, targetClass); + CacheOperation 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. + CacheOperation 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 CacheOperation 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. + CacheOperation opDef = findCacheOperation(specificMethod); + if (opDef != null) { + return opDef; + } + + // Second try is the caching operation on the target class. + opDef = findCacheOperation(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 findCacheOperation(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 CacheOperation 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 CacheOperation findCacheOperation(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/BeanFactoryCacheOperationSourceAdvisor.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java new file mode 100644 index 00000000000..21ebfe46adc --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java @@ -0,0 +1,62 @@ +/* + * 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 CacheOperationSource}, used to include a + * cache advice bean for methods that are cacheable. + * + * @author Costin Leau + */ +@SuppressWarnings("serial") +public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { + + private CacheOperationSource cacheDefinitionSource; + + private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() { + @Override + protected CacheOperationSource getCacheOperationSource() { + 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(CacheOperationSource 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/CacheEvictOperation.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java new file mode 100644 index 00000000000..bfbbdc4dbc2 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java @@ -0,0 +1,43 @@ +/* + * 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; + +/** + * Class describing an 'evict' operation. + * + * @author Costin Leau + */ +public class CacheEvictOperation extends CacheOperation { + + private boolean cacheWide = false; + + public boolean isCacheWide() { + return cacheWide; + } + + public void setCacheWide(boolean cacheWide) { + this.cacheWide = cacheWide; + } + + @Override + protected StringBuilder getOperationDescription() { + StringBuilder sb = super.getOperationDescription(); + sb.append(","); + sb.append(cacheWide); + return sb; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java new file mode 100644 index 00000000000..569ff2f0fcf --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java @@ -0,0 +1,128 @@ +/* + * 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 CacheOperation}. + * + * @author Costin Leau + */ +public abstract class CacheOperation { + + 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 CacheOperation && 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. + *

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 getOperationDescription().toString(); + } + + /** + * Return an identifying description for this caching operation. + *

Available to subclasses, for inclusion in their toString() result. + */ + protected StringBuilder getOperationDescription() { + 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/CacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java new file mode 100644 index 00000000000..f22c0b11189 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSource.java @@ -0,0 +1,41 @@ +/* + * 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 CacheOperationSource { + + /** + * 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 CacheOperation} the matching cache operation, + * or null if none found + */ + CacheOperation getCacheOperation(Method method, Class targetClass); +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java new file mode 100644 index 00000000000..e519e7cb088 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java @@ -0,0 +1,68 @@ +/* + * 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 CacheOperationSource} has an attribute for a given method. + * + * @author Costin Leau + */ +@SuppressWarnings("serial") +abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { + + public boolean matches(Method method, Class targetClass) { + CacheOperationSource cas = getCacheOperationSource(); + return (cas == null || cas.getCacheOperation(method, targetClass) != null); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof CacheOperationSourcePointcut)) { + return false; + } + CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other; + return ObjectUtils.nullSafeEquals(getCacheOperationSource(), + otherPc.getCacheOperationSource()); + } + + @Override + public int hashCode() { + return CacheOperationSourcePointcut.class.hashCode(); + } + + @Override + public String toString() { + return getClass().getName() + ": " + getCacheOperationSource(); + } + + + /** + * Obtain the underlying CacheOperationDefinitionSource (may be null). + * To be implemented by subclasses. + */ + protected abstract CacheOperationSource getCacheOperationSource(); +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java new file mode 100644 index 00000000000..4b11483c030 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * Class describing an 'update' operation. + * + * @author Costin Leau + */ +public class CacheUpdateOperation extends CacheOperation { + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java new file mode 100644 index 00000000000..d42b8148c57 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CompositeCacheOperationSource.java @@ -0,0 +1,63 @@ +/* + * 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 CacheOperationSource} implementation that iterates + * over a given array of {@link CacheOperationSource} instances. + * + * @author Costin Leau + */ +@SuppressWarnings("serial") +public class CompositeCacheOperationSource implements CacheOperationSource, Serializable { + + private final CacheOperationSource[] cacheDefinitionSources; + + /** + * Create a new CompositeCachingDefinitionSource for the given sources. + * @param cacheDefinitionSourcess the CacheDefinitionSource instances to combine + */ + public CompositeCacheOperationSource(CacheOperationSource[] cacheDefinitionSources) { + Assert.notNull(cacheDefinitionSources, "cacheDefinitionSource array must not be null"); + this.cacheDefinitionSources = cacheDefinitionSources; + } + + /** + * Return the CacheDefinitionSource instances that this + * CompositeCachingDefinitionSource combines. + */ + public final CacheOperationSource[] getCacheDefinitionSources() { + return this.cacheDefinitionSources; + } + + + public CacheOperation getCacheOperation(Method method, Class targetClass) { + for (CacheOperationSource source : cacheDefinitionSources) { + CacheOperation definition = source.getCacheOperation(method, targetClass); + if (definition != null) { + return definition; + } + } + + return null; + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultValue.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultValue.java new file mode 100644 index 00000000000..ec699f89aef --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultValue.java @@ -0,0 +1,37 @@ +/* + * Copyright 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.cache.Cache.ValueWrapper; + +/** + * Default implementation for {@link org.springframework.cache.Cache.ValueWrapper}. + * + * @author Costin Leau + */ +public class DefaultValue implements ValueWrapper { + + private final V value; + + public DefaultValue(V value) { + this.value = value; + } + + public V get() { + return value; + } +}