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 b31afda05fe..32cedfe6de7 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 @@ -1,82 +1,82 @@ -/* - * Copyright 2002-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; - -/** - * Interface that defines the common cache operations. - * - * Note: Due to the generic use of caching, it is recommended that - * implementations allow storage of null values (for example to - * cache methods that return null). - * - * @author Costin Leau - * @since 3.1 - */ -public interface Cache { - - /** - * Return the cache name. - */ - String getName(); - - /** - * Return the the underlying native cache provider. - */ - Object getNativeCache(); - - /** - * Return 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 - */ - ValueWrapper get(Object key); - - /** - * Associate 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 the key with which the specified value is to be associated - * @param value the value to be associated with the specified key - */ - void put(Object key, Object value); - - /** - * Evict the mapping for this key from this cache if it is present. - * @param key the key whose mapping is to be removed from the cache - */ - void evict(Object key); - - /** - * Remove all mappings from the cache. - */ - void clear(); - - - /** - * A (wrapper) object representing a cache value. - */ - interface ValueWrapper { - - /** - * Return the actual value in the cache. - */ - Object get(); - } - -} +/* + * Copyright 2002-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; + +/** + * Interface that defines the common cache operations. + * + * Note: Due to the generic use of caching, it is recommended that + * implementations allow storage of null values (for example to + * cache methods that return {@code null}). + * + * @author Costin Leau + * @since 3.1 + */ +public interface Cache { + + /** + * Return the cache name. + */ + String getName(); + + /** + * Return the the underlying native cache provider. + */ + Object getNativeCache(); + + /** + * Return 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 + */ + ValueWrapper get(Object key); + + /** + * Associate 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 the key with which the specified value is to be associated + * @param value the value to be associated with the specified key + */ + void put(Object key, Object value); + + /** + * Evict the mapping for this key from this cache if it is present. + * @param key the key whose mapping is to be removed from the cache + */ + void evict(Object key); + + /** + * Remove all mappings from the cache. + */ + void clear(); + + + /** + * A (wrapper) object representing a cache value. + */ + interface ValueWrapper { + + /** + * Return the actual value in the cache. + */ + Object get(); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/CacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/CacheManager.java index 186f188cdf7..86228014eac 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/CacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/CacheManager.java @@ -1,42 +1,42 @@ -/* - * Copyright 2002-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; - -import java.util.Collection; - -/** - * A manager for a set of {@link Cache}s. - * - * @author Costin Leau - * @since 3.1 - */ -public interface CacheManager { - - /** - * Return the cache associated with the given name. - * @param name cache identifier (must not be null) - * @return associated cache, or null if none is found - */ - Cache getCache(String name); - - /** - * Return a collection of the caches known by this cache manager. - * @return names of caches known by the cache manager. - */ - Collection getCacheNames(); - -} +/* + * Copyright 2002-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; + +import java.util.Collection; + +/** + * A manager for a set of {@link Cache}s. + * + * @author Costin Leau + * @since 3.1 + */ +public interface CacheManager { + + /** + * Return the cache associated with the given name. + * @param name cache identifier (must not be {@code null}) + * @return associated cache, or {@code null} if none is found + */ + Cache getCache(String name); + + /** + * Return a collection of the caches known by this cache manager. + * @return names of caches known by the cache manager. + */ + Collection getCacheNames(); + +} 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 index 9aab40515bf..023a158d0cf 100644 --- 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 @@ -1,130 +1,130 @@ -/* - * Copyright 2002-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.ArrayList; -import java.util.Collection; -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}, {@link CachePut} 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 - * @since 3.1 - */ -@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 default 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 SpringCacheAnnotationParser()); - } - - /** - * 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 Collection findCacheOperations(Class clazz) { - return determineCacheOperations(clazz); - } - - @Override - protected Collection findCacheOperations(Method method) { - return determineCacheOperations(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 Collection determineCacheOperations(AnnotatedElement ae) { - Collection ops = null; - - for (CacheAnnotationParser annotationParser : this.annotationParsers) { - Collection annOps = annotationParser.parseCacheAnnotations(ae); - if (annOps != null) { - if (ops == null) { - ops = new ArrayList(); - } - ops.addAll(annOps); - } - } - return ops; - } - - /** - * By default, only public methods can be made cacheable. - */ - @Override - protected boolean allowPublicMethodsOnly() { - return this.publicMethodsOnly; - } -} \ No newline at end of file +/* + * Copyright 2002-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.ArrayList; +import java.util.Collection; +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}, {@link CachePut} 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 + * @since 3.1 + */ +@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 default 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 SpringCacheAnnotationParser()); + } + + /** + * 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 Collection findCacheOperations(Class clazz) { + return determineCacheOperations(clazz); + } + + @Override + protected Collection findCacheOperations(Method method) { + return determineCacheOperations(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 Collection determineCacheOperations(AnnotatedElement ae) { + Collection ops = null; + + for (CacheAnnotationParser annotationParser : this.annotationParsers) { + Collection annOps = annotationParser.parseCacheAnnotations(ae); + if (annOps != null) { + if (ops == null) { + ops = new ArrayList(); + } + ops.addAll(annOps); + } + } + return ops; + } + + /** + * By default, only public methods can be made cacheable. + */ + @Override + protected boolean allowPublicMethodsOnly() { + return this.publicMethodsOnly; + } +} 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 d5a54abe9d9..fd86d800360 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 @@ -1,48 +1,47 @@ -/* - * Copyright 2002-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.lang.reflect.AnnotatedElement; -import java.util.Collection; - -import org.springframework.cache.interceptor.CacheOperation; - - -/** - * Strategy interface for parsing known caching annotation types. - * {@link AnnotationCacheDefinitionSource} delegates to such - * parsers for supporting specific annotation types such as Spring's own - * {@link Cacheable}, {@link CachePut} or {@link CacheEvict}. - * - * @author Costin Leau - * @since 3.1 - */ -public interface CacheAnnotationParser { - - /** - * Parses the cache definition for the given method or class, - * based on a known annotation type. - *

This essentially parses a known cache annotation into Spring's - * metadata attribute class. Returns null if the method/class - * is not cacheable. - * @param ae the annotated method or class - * @return CacheOperation the configured caching operation, - * or null if none was found - * @see AnnotationCacheOperationSource#determineCacheOperation - */ - Collection parseCacheAnnotations(AnnotatedElement ae); -} +/* + * Copyright 2002-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.lang.reflect.AnnotatedElement; +import java.util.Collection; + +import org.springframework.cache.interceptor.CacheOperation; + +/** + * Strategy interface for parsing known caching annotation types. + * {@link AnnotationCacheDefinitionSource} delegates to such + * parsers for supporting specific annotation types such as Spring's own + * {@link Cacheable}, {@link CachePut} or {@link CacheEvict}. + * + * @author Costin Leau + * @since 3.1 + */ +public interface CacheAnnotationParser { + + /** + * Parses the cache definition for the given method or class, + * based on a known annotation type. + *

This essentially parses a known cache annotation into Spring's + * metadata attribute class. Returns {@code null} if the method/class + * is not cacheable. + * @param ae the annotated method or class + * @return CacheOperation the configured caching operation, + * or {@code null} if none was found + * @see AnnotationCacheOperationSource#determineCacheOperation + */ + Collection parseCacheAnnotations(AnnotatedElement ae); +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java index 0aa4947f83b..8807a5cc4b1 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java @@ -1,43 +1,44 @@ -/* - * 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Group annotation for multiple cache annotations (of different or the same type). - * - * @author Costin Leau - * @since 3.1 - */ -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface CacheDefinitions { - - Cacheable[] cacheable() default {}; - - CachePut[] put() default {}; - - CacheEvict[] evict() default {}; -} +/* + * Copyright 2002-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.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Group annotation for multiple cache annotations (of different or the same type). + * + * @author Costin Leau + * @author Chris Beams + * @since 3.1 + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface CacheDefinitions { + + Cacheable[] cacheable() default {}; + + CachePut[] put() default {}; + + CacheEvict[] evict() default {}; +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheEvict.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheEvict.java index 6414d17efd8..a96f8f8f65e 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheEvict.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheEvict.java @@ -1,66 +1,66 @@ -/* - * Copyright 2002-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.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation indicating that a method (or all methods on a class) trigger(s) - * a cache invalidate operation. - * - * @author Costin Leau - * @since 3.1 - */ -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface CacheEvict { - - /** - * Qualifier value for the specified cached operation. - *

May be used to determine the target cache (or caches), matching the qualifier - * value (or the bean name(s)) of (a) specific bean definition. - */ - String[] value(); - - /** - * Spring Expression Language (SpEL) attribute for computing the key dynamically. - *

Default is "", meaning all method parameters are considered as a key. - */ - String key() default ""; - - /** - * Spring Expression Language (SpEL) attribute used for conditioning the method caching. - *

Default is "", meaning the method is always cached. - */ - String condition() default ""; - - /** - * Whether or not all the entries inside the cache(s) are removed or not. By - * default, only the value under the associated key is removed. - *

Note that specifying setting this parameter to true and specifying a - * {@link CacheKey key} is not allowed. - */ - boolean allEntries() default false; - -} +/* + * Copyright 2002-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.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation indicating that a method (or all methods on a class) trigger(s) + * a cache invalidate operation. + * + * @author Costin Leau + * @since 3.1 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface CacheEvict { + + /** + * Qualifier value for the specified cached operation. + *

May be used to determine the target cache (or caches), matching the qualifier + * value (or the bean name(s)) of (a) specific bean definition. + */ + String[] value(); + + /** + * Spring Expression Language (SpEL) attribute for computing the key dynamically. + *

Default is "", meaning all method parameters are considered as a key. + */ + String key() default ""; + + /** + * Spring Expression Language (SpEL) attribute used for conditioning the method caching. + *

Default is "", meaning the method is always cached. + */ + String condition() default ""; + + /** + * Whether or not all the entries inside the cache(s) are removed or not. By + * default, only the value under the associated key is removed. + *

Note that specifying setting this parameter to true and specifying a + * {@link CacheKey key} is not allowed. + */ + boolean allEntries() default false; + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java index dbeb6aeef6f..0cc7f883f19 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java @@ -1,62 +1,61 @@ -/* - * 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.cache.Cache; - -/** - * - * Annotation indicating that a method (or all methods on a class) trigger(s) - * a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation, - * this annotation does not cause the target method to be skipped - rather it - * always causes the method to be invoked and its result to be placed into the cache. - * - * @author Costin Leau - * @since 3.1 - */ -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface CachePut { - - /** - * Name of the caches in which the update takes place. - *

May be used to determine the target cache (or caches), matching the - * qualifier value (or the bean name(s)) of (a) specific bean definition. - */ - String[] value(); - - /** - * Spring Expression Language (SpEL) attribute for computing the key dynamically. - *

Default is "", meaning all method parameters are considered as a key. - */ - String key() default ""; - - /** - * Spring Expression Language (SpEL) attribute used for conditioning the cache update. - *

Default is "", meaning the method result is always cached. - */ - String condition() default ""; -} +/* + * 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.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.cache.Cache; + +/** + * Annotation indicating that a method (or all methods on a class) trigger(s) + * a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation, + * this annotation does not cause the target method to be skipped - rather it + * always causes the method to be invoked and its result to be placed into the cache. + * + * @author Costin Leau + * @since 3.1 + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface CachePut { + + /** + * Name of the caches in which the update takes place. + *

May be used to determine the target cache (or caches), matching the + * qualifier value (or the bean name(s)) of (a) specific bean definition. + */ + String[] value(); + + /** + * Spring Expression Language (SpEL) attribute for computing the key dynamically. + *

Default is "", meaning all method parameters are considered as a key. + */ + String key() default ""; + + /** + * Spring Expression Language (SpEL) attribute used for conditioning the cache update. + *

Default is "", meaning the method result is always cached. + */ + String condition() default ""; +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/Cacheable.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/Cacheable.java index c6a33e9a5d7..447ce62b4f8 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/Cacheable.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/Cacheable.java @@ -1,59 +1,59 @@ -/* - * Copyright 2002-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.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation indicating that a method (or all the methods on a class) can be cached. - * - *

The method arguments and signature are used for computing the key while the - * returned instance is used as the cache value. - * - * @author Costin Leau - * @since 3.1 - */ -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface Cacheable { - - /** - * Name of the caches in which the update takes place. - *

May be used to determine the target cache (or caches), matching the - * qualifier value (or the bean name(s)) of (a) specific bean definition. - */ - String[] value(); - - /** - * Spring Expression Language (SpEL) attribute for computing the key dynamically. - *

Default is "", meaning all method parameters are considered as a key. - */ - String key() default ""; - - /** - * Spring Expression Language (SpEL) attribute used for conditioning the method caching. - *

Default is "", meaning the method is always cached. - */ - String condition() default ""; -} +/* + * Copyright 2002-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.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation indicating that a method (or all the methods on a class) can be cached. + * + *

The method arguments and signature are used for computing the key while the + * returned instance is used as the cache value. + * + * @author Costin Leau + * @since 3.1 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface Cacheable { + + /** + * Name of the caches in which the update takes place. + *

May be used to determine the target cache (or caches), matching the + * qualifier value (or the bean name(s)) of (a) specific bean definition. + */ + String[] value(); + + /** + * Spring Expression Language (SpEL) attribute for computing the key dynamically. + *

Default is "", meaning all method parameters are considered as a key. + */ + String key() default ""; + + /** + * Spring Expression Language (SpEL) attribute used for conditioning the method caching. + *

Default is "", meaning the method is always cached. + */ + String condition() default ""; +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java index 4cffa9f6b28..95009ff1dab 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java @@ -1,126 +1,127 @@ -/* - * Copyright 2002-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.util.ArrayList; -import java.util.Collection; - -import org.springframework.cache.interceptor.CacheEvictOperation; -import org.springframework.cache.interceptor.CacheOperation; -import org.springframework.cache.interceptor.CachePutOperation; -import org.springframework.cache.interceptor.CacheableOperation; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.util.ObjectUtils; - -/** - * Strategy implementation for parsing Spring's {@link Cacheable}, {@link CacheEvict} and {@link CachePut} annotations. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -@SuppressWarnings("serial") -public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable { - - public Collection parseCacheAnnotations(AnnotatedElement ae) { - Collection ops = null; - - Cacheable cache = AnnotationUtils.getAnnotation(ae, Cacheable.class); - if (cache != null) { - ops = lazyInit(ops); - ops.add(parseCacheableAnnotation(ae, cache)); - } - CacheEvict evict = AnnotationUtils.getAnnotation(ae, CacheEvict.class); - if (evict != null) { - ops = lazyInit(ops); - ops.add(parseEvictAnnotation(ae, evict)); - } - CachePut update = AnnotationUtils.getAnnotation(ae, CachePut.class); - if (update != null) { - ops = lazyInit(ops); - ops.add(parseUpdateAnnotation(ae, update)); - } - CacheDefinitions definition = AnnotationUtils.getAnnotation(ae, CacheDefinitions.class); - if (definition != null) { - ops = lazyInit(ops); - ops.addAll(parseDefinitionAnnotation(ae, definition)); - } - return ops; - } - - private Collection lazyInit(Collection ops) { - return (ops != null ? ops : new ArrayList(2)); - } - - CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, Cacheable ann) { - CacheableOperation cuo = new CacheableOperation(); - cuo.setCacheNames(ann.value()); - cuo.setCondition(ann.condition()); - cuo.setKey(ann.key()); - cuo.setName(ae.toString()); - return cuo; - } - - CacheEvictOperation parseEvictAnnotation(AnnotatedElement ae, CacheEvict ann) { - CacheEvictOperation ceo = new CacheEvictOperation(); - ceo.setCacheNames(ann.value()); - ceo.setCondition(ann.condition()); - ceo.setKey(ann.key()); - ceo.setCacheWide(ann.allEntries()); - ceo.setName(ae.toString()); - return ceo; - } - - CacheOperation parseUpdateAnnotation(AnnotatedElement ae, CachePut ann) { - CachePutOperation cuo = new CachePutOperation(); - cuo.setCacheNames(ann.value()); - cuo.setCondition(ann.condition()); - cuo.setKey(ann.key()); - cuo.setName(ae.toString()); - return cuo; - } - - Collection parseDefinitionAnnotation(AnnotatedElement ae, CacheDefinitions ann) { - Collection ops = null; - - Cacheable[] cacheables = ann.cacheable(); - if (!ObjectUtils.isEmpty(cacheables)) { - ops = lazyInit(ops); - for (Cacheable cacheable : cacheables) { - ops.add(parseCacheableAnnotation(ae, cacheable)); - } - } - CacheEvict[] evicts = ann.evict(); - if (!ObjectUtils.isEmpty(evicts)) { - ops = lazyInit(ops); - for (CacheEvict evict : evicts) { - ops.add(parseEvictAnnotation(ae, evict)); - } - } - CachePut[] updates = ann.put(); - if (!ObjectUtils.isEmpty(updates)) { - ops = lazyInit(ops); - for (CachePut update : updates) { - ops.add(parseUpdateAnnotation(ae, update)); - } - } - - return ops; - } -} \ No newline at end of file +/* + * Copyright 2002-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.util.ArrayList; +import java.util.Collection; + +import org.springframework.cache.interceptor.CacheEvictOperation; +import org.springframework.cache.interceptor.CacheOperation; +import org.springframework.cache.interceptor.CachePutOperation; +import org.springframework.cache.interceptor.CacheableOperation; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.util.ObjectUtils; + +/** + * Strategy implementation for parsing Spring's {@link Cacheable}, + * {@link CacheEvict} and {@link CachePut} annotations. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +@SuppressWarnings("serial") +public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable { + + public Collection parseCacheAnnotations(AnnotatedElement ae) { + Collection ops = null; + + Cacheable cache = AnnotationUtils.getAnnotation(ae, Cacheable.class); + if (cache != null) { + ops = lazyInit(ops); + ops.add(parseCacheableAnnotation(ae, cache)); + } + CacheEvict evict = AnnotationUtils.getAnnotation(ae, CacheEvict.class); + if (evict != null) { + ops = lazyInit(ops); + ops.add(parseEvictAnnotation(ae, evict)); + } + CachePut update = AnnotationUtils.getAnnotation(ae, CachePut.class); + if (update != null) { + ops = lazyInit(ops); + ops.add(parseUpdateAnnotation(ae, update)); + } + CacheDefinitions definition = AnnotationUtils.getAnnotation(ae, CacheDefinitions.class); + if (definition != null) { + ops = lazyInit(ops); + ops.addAll(parseDefinitionAnnotation(ae, definition)); + } + return ops; + } + + private Collection lazyInit(Collection ops) { + return (ops != null ? ops : new ArrayList(2)); + } + + CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, Cacheable ann) { + CacheableOperation cuo = new CacheableOperation(); + cuo.setCacheNames(ann.value()); + cuo.setCondition(ann.condition()); + cuo.setKey(ann.key()); + cuo.setName(ae.toString()); + return cuo; + } + + CacheEvictOperation parseEvictAnnotation(AnnotatedElement ae, CacheEvict ann) { + CacheEvictOperation ceo = new CacheEvictOperation(); + ceo.setCacheNames(ann.value()); + ceo.setCondition(ann.condition()); + ceo.setKey(ann.key()); + ceo.setCacheWide(ann.allEntries()); + ceo.setName(ae.toString()); + return ceo; + } + + CacheOperation parseUpdateAnnotation(AnnotatedElement ae, CachePut ann) { + CachePutOperation cuo = new CachePutOperation(); + cuo.setCacheNames(ann.value()); + cuo.setCondition(ann.condition()); + cuo.setKey(ann.key()); + cuo.setName(ae.toString()); + return cuo; + } + + Collection parseDefinitionAnnotation(AnnotatedElement ae, CacheDefinitions ann) { + Collection ops = null; + + Cacheable[] cacheables = ann.cacheable(); + if (!ObjectUtils.isEmpty(cacheables)) { + ops = lazyInit(ops); + for (Cacheable cacheable : cacheables) { + ops.add(parseCacheableAnnotation(ae, cacheable)); + } + } + CacheEvict[] evicts = ann.evict(); + if (!ObjectUtils.isEmpty(evicts)) { + ops = lazyInit(ops); + for (CacheEvict evict : evicts) { + ops.add(parseEvictAnnotation(ae, evict)); + } + } + CachePut[] updates = ann.put(); + if (!ObjectUtils.isEmpty(updates)) { + ops = lazyInit(ops); + for (CachePut update : updates) { + ops.add(parseUpdateAnnotation(ae, update)); + } + } + + return ops; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/package-info.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/package-info.java index e9d9a11f3bd..6c230a8eaa5 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/package-info.java @@ -1,9 +1,8 @@ - -/** - * JDK 1.5+ annotation for caching demarcation. - * Hooked into Spring's caching interception infrastructure - * via CacheOperationSource implementation. - * - */ -package org.springframework.cache.annotation; - + +/** + * Annotations and supporting classes for declarative cache management. + * Hooked into Spring's caching interception infrastructure + * via {@link org.springframework.cache.interceptor.CacheOperationSource + * CacheOperationSource} implementation. + */ +package org.springframework.cache.annotation; diff --git a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java index 945f920ef63..0fa632d2a0f 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java @@ -1,145 +1,145 @@ -/* - * Copyright 2002-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.concurrent; - -import java.io.Serializable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.springframework.cache.Cache; -import org.springframework.cache.support.ValueWrapperImpl; - -/** - * Simple {@link Cache} implementation based on the core JDK - * java.util.concurrent package. - * - *

Useful for testing or simple caching scenarios, typically in combination - * with {@link org.springframework.cache.support.SimpleCacheManager} or - * dynamically through {@link ConcurrentMapCacheManager}. - * - *

Note: As {@link ConcurrentHashMap} (the default implementation used) - * does not allow for null values to be stored, this class will replace - * them with a predefined internal object. This behavior can be changed through the - * {@link #ConcurrentMapCache(String, ConcurrentMap, boolean)} constructor. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -public class ConcurrentMapCache implements Cache { - - private static final Object NULL_HOLDER = new NullHolder(); - - private final String name; - - private final ConcurrentMap store; - - private final boolean allowNullValues; - - - /** - * Create a new ConcurrentMapCache with the specified name. - * @param name the name of the cache - */ - public ConcurrentMapCache(String name) { - this(name, new ConcurrentHashMap(), true); - } - - /** - * Create a new ConcurrentMapCache with the specified name. - * @param name the name of the cache - */ - public ConcurrentMapCache(String name, boolean allowNullValues) { - this(name, new ConcurrentHashMap(), allowNullValues); - } - - /** - * Create a new ConcurrentMapCache with the specified name and the - * given internal ConcurrentMap to use. - * @param name the name of the cache - * @param store the ConcurrentMap to use as an internal store - * @param allowNullValues whether to allow null values - * (adapting them to an internal null holder value) - */ - public ConcurrentMapCache(String name, ConcurrentMap store, boolean allowNullValues) { - this.name = name; - this.store = store; - this.allowNullValues = allowNullValues; - } - - - public String getName() { - return this.name; - } - - public ConcurrentMap getNativeCache() { - return this.store; - } - - public boolean isAllowNullValues() { - return this.allowNullValues; - } - - public ValueWrapper get(Object key) { - Object value = this.store.get(key); - return (value != null ? new ValueWrapperImpl(fromStoreValue(value)) : null); - } - - public void put(Object key, Object value) { - this.store.put(key, toStoreValue(value)); - } - - public void evict(Object key) { - this.store.remove(key); - } - - public void clear() { - this.store.clear(); - } - - - /** - * Convert the given value from the internal store to a user value - * returned from the get method (adapting null). - * @param userValue the store value - * @return the value to return to the user - */ - protected Object fromStoreValue(Object storeValue) { - if (this.allowNullValues && storeValue == NULL_HOLDER) { - return null; - } - return storeValue; - } - - /** - * Convert the given user value, as passed into the put method, - * to a value in the internal store (adapting null). - * @param userValue the given user value - * @return the value to store - */ - protected Object toStoreValue(Object userValue) { - if (this.allowNullValues && userValue == null) { - return NULL_HOLDER; - } - return userValue; - } - - - private static class NullHolder implements Serializable { - } - -} +/* + * Copyright 2002-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.concurrent; + +import java.io.Serializable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.springframework.cache.Cache; +import org.springframework.cache.support.ValueWrapperImpl; + +/** + * Simple {@link Cache} implementation based on the core JDK + * {@code java.util.concurrent} package. + * + *

Useful for testing or simple caching scenarios, typically in combination + * with {@link org.springframework.cache.support.SimpleCacheManager} or + * dynamically through {@link ConcurrentMapCacheManager}. + * + *

Note: As {@link ConcurrentHashMap} (the default implementation used) + * does not allow for {@code null} values to be stored, this class will replace + * them with a predefined internal object. This behavior can be changed through the + * {@link #ConcurrentMapCache(String, ConcurrentMap, boolean)} constructor. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +public class ConcurrentMapCache implements Cache { + + private static final Object NULL_HOLDER = new NullHolder(); + + private final String name; + + private final ConcurrentMap store; + + private final boolean allowNullValues; + + + /** + * Create a new ConcurrentMapCache with the specified name. + * @param name the name of the cache + */ + public ConcurrentMapCache(String name) { + this(name, new ConcurrentHashMap(), true); + } + + /** + * Create a new ConcurrentMapCache with the specified name. + * @param name the name of the cache + */ + public ConcurrentMapCache(String name, boolean allowNullValues) { + this(name, new ConcurrentHashMap(), allowNullValues); + } + + /** + * Create a new ConcurrentMapCache with the specified name and the + * given internal ConcurrentMap to use. + * @param name the name of the cache + * @param store the ConcurrentMap to use as an internal store + * @param allowNullValues whether to allow null values + * (adapting them to an internal null holder value) + */ + public ConcurrentMapCache(String name, ConcurrentMap store, boolean allowNullValues) { + this.name = name; + this.store = store; + this.allowNullValues = allowNullValues; + } + + + public String getName() { + return this.name; + } + + public ConcurrentMap getNativeCache() { + return this.store; + } + + public boolean isAllowNullValues() { + return this.allowNullValues; + } + + public ValueWrapper get(Object key) { + Object value = this.store.get(key); + return (value != null ? new ValueWrapperImpl(fromStoreValue(value)) : null); + } + + public void put(Object key, Object value) { + this.store.put(key, toStoreValue(value)); + } + + public void evict(Object key) { + this.store.remove(key); + } + + public void clear() { + this.store.clear(); + } + + + /** + * Convert the given value from the internal store to a user value + * returned from the get method (adapting null). + * @param userValue the store value + * @return the value to return to the user + */ + protected Object fromStoreValue(Object storeValue) { + if (this.allowNullValues && storeValue == NULL_HOLDER) { + return null; + } + return storeValue; + } + + /** + * Convert the given user value, as passed into the put method, + * to a value in the internal store (adapting null). + * @param userValue the given user value + * @return the value to store + */ + protected Object toStoreValue(Object userValue) { + if (this.allowNullValues && userValue == null) { + return NULL_HOLDER; + } + return userValue; + } + + + private static class NullHolder implements Serializable { + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java index c7a9474ecdd..26b242310b9 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheFactoryBean.java @@ -1,101 +1,101 @@ -/* - * Copyright 2002-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.concurrent; - -import java.util.concurrent.ConcurrentMap; - -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.StringUtils; - -/** - * {@link FactoryBean} for easy configuration of a {@link ConcurrentMapCache} - * when used within a Spring container. Can be configured through bean properties; - * uses the assigned Spring bean name as the default cache name. - * - *

Useful for testing or simple caching scenarios, typically in combination - * with {@link org.springframework.cache.support.SimpleCacheManager} or - * dynamically through {@link ConcurrentMapCacheManager}. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -public class ConcurrentMapCacheFactoryBean - implements FactoryBean, BeanNameAware, InitializingBean { - - private String name = ""; - - private ConcurrentMap store; - - private boolean allowNullValues = true; - - private ConcurrentMapCache cache; - - - /** - * Specify the name of the cache. - *

Default is "" (empty String). - */ - public void setName(String name) { - this.name = name; - } - - /** - * Specify the ConcurrentMap to use as an internal store - * (possibly pre-populated). - *

Default is a standard {@link java.util.concurrent.ConcurrentHashMap}. - */ - public void setStore(ConcurrentMap store) { - this.store = store; - } - - /** - * Set whether to allow null values - * (adapting them to an internal null holder value). - *

Default is "true". - */ - public void setAllowNullValues(boolean allowNullValues) { - this.allowNullValues = allowNullValues; - } - - public void setBeanName(String beanName) { - if (!StringUtils.hasLength(this.name)) { - setName(beanName); - } - } - - public void afterPropertiesSet() { - this.cache = (this.store != null ? new ConcurrentMapCache(this.name, this.store, this.allowNullValues) : - new ConcurrentMapCache(this.name, this.allowNullValues)); - } - - - public ConcurrentMapCache getObject() { - return this.cache; - } - - public Class getObjectType() { - return ConcurrentMapCache.class; - } - - public boolean isSingleton() { - return true; - } - -} +/* + * Copyright 2002-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.concurrent; + +import java.util.concurrent.ConcurrentMap; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.StringUtils; + +/** + * {@link FactoryBean} for easy configuration of a {@link ConcurrentMapCache} + * when used within a Spring container. Can be configured through bean properties; + * uses the assigned Spring bean name as the default cache name. + * + *

Useful for testing or simple caching scenarios, typically in combination + * with {@link org.springframework.cache.support.SimpleCacheManager} or + * dynamically through {@link ConcurrentMapCacheManager}. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +public class ConcurrentMapCacheFactoryBean + implements FactoryBean, BeanNameAware, InitializingBean { + + private String name = ""; + + private ConcurrentMap store; + + private boolean allowNullValues = true; + + private ConcurrentMapCache cache; + + + /** + * Specify the name of the cache. + *

Default is "" (empty String). + */ + public void setName(String name) { + this.name = name; + } + + /** + * Specify the ConcurrentMap to use as an internal store + * (possibly pre-populated). + *

Default is a standard {@link java.util.concurrent.ConcurrentHashMap}. + */ + public void setStore(ConcurrentMap store) { + this.store = store; + } + + /** + * Set whether to allow {@code null} values + * (adapting them to an internal null holder value). + *

Default is "true". + */ + public void setAllowNullValues(boolean allowNullValues) { + this.allowNullValues = allowNullValues; + } + + public void setBeanName(String beanName) { + if (!StringUtils.hasLength(this.name)) { + setName(beanName); + } + } + + public void afterPropertiesSet() { + this.cache = (this.store != null ? new ConcurrentMapCache(this.name, this.store, this.allowNullValues) : + new ConcurrentMapCache(this.name, this.allowNullValues)); + } + + + public ConcurrentMapCache getObject() { + return this.cache; + } + + public Class getObjectType() { + return ConcurrentMapCache.class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheManager.java index 2d447e6d822..fd59da23c8a 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheManager.java @@ -1,101 +1,101 @@ -/* - * Copyright 2002-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.concurrent; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; - -/** - * {@link CacheManager} implementation that lazily builds {@link ConcurrentMapCache} - * instances for each {@link #getCache} request. Also supports a 'static' mode where - * the set of cache names is pre-defined through {@link #setCacheNames}, with no - * dynamic creation of further cache regions at runtime. - * - * @author Juergen Hoeller - * @since 3.1 - */ -public class ConcurrentMapCacheManager implements CacheManager { - - private final ConcurrentMap cacheMap = new ConcurrentHashMap(); - - private boolean dynamic = true; - - - /** - * Construct a dynamic ConcurrentMapCacheManager, - * lazily creating cache instances as they are being requested. - */ - public ConcurrentMapCacheManager() { - } - - /** - * Construct a static ConcurrentMapCacheManager, - * managing caches for the specified cache names only. - */ - public ConcurrentMapCacheManager(String... cacheNames) { - setCacheNames(Arrays.asList(cacheNames)); - } - - - /** - * Specify the set of cache names for this CacheManager's 'static' mode. - *

The number of caches and their names will be fixed after a call to this method, - * with no creation of further cache regions at runtime. - */ - public void setCacheNames(Collection cacheNames) { - if (cacheNames != null) { - for (String name : cacheNames) { - this.cacheMap.put(name, createConcurrentMapCache(name)); - } - this.dynamic = false; - } - } - - public Collection getCacheNames() { - return Collections.unmodifiableSet(this.cacheMap.keySet()); - } - - public Cache getCache(String name) { - Cache cache = this.cacheMap.get(name); - if (cache == null && this.dynamic) { - synchronized (this.cacheMap) { - cache = this.cacheMap.get(name); - if (cache == null) { - cache = createConcurrentMapCache(name); - this.cacheMap.put(name, cache); - } - } - } - return cache; - } - - /** - * Create a new ConcurrentMapCache instance for the specified cache name. - * @param name the name of the cache - * @return the ConcurrentMapCache (or a decorator thereof) - */ - protected Cache createConcurrentMapCache(String name) { - return new ConcurrentMapCache(name); - } - -} +/* + * Copyright 2002-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.concurrent; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +/** + * {@link CacheManager} implementation that lazily builds {@link ConcurrentMapCache} + * instances for each {@link #getCache} request. Also supports a 'static' mode where + * the set of cache names is pre-defined through {@link #setCacheNames}, with no + * dynamic creation of further cache regions at runtime. + * + * @author Juergen Hoeller + * @since 3.1 + */ +public class ConcurrentMapCacheManager implements CacheManager { + + private final ConcurrentMap cacheMap = new ConcurrentHashMap(); + + private boolean dynamic = true; + + + /** + * Construct a dynamic ConcurrentMapCacheManager, + * lazily creating cache instances as they are being requested. + */ + public ConcurrentMapCacheManager() { + } + + /** + * Construct a static ConcurrentMapCacheManager, + * managing caches for the specified cache names only. + */ + public ConcurrentMapCacheManager(String... cacheNames) { + setCacheNames(Arrays.asList(cacheNames)); + } + + + /** + * Specify the set of cache names for this CacheManager's 'static' mode. + *

The number of caches and their names will be fixed after a call to this method, + * with no creation of further cache regions at runtime. + */ + public void setCacheNames(Collection cacheNames) { + if (cacheNames != null) { + for (String name : cacheNames) { + this.cacheMap.put(name, createConcurrentMapCache(name)); + } + this.dynamic = false; + } + } + + public Collection getCacheNames() { + return Collections.unmodifiableSet(this.cacheMap.keySet()); + } + + public Cache getCache(String name) { + Cache cache = this.cacheMap.get(name); + if (cache == null && this.dynamic) { + synchronized (this.cacheMap) { + cache = this.cacheMap.get(name); + if (cache == null) { + cache = createConcurrentMapCache(name); + this.cacheMap.put(name, cache); + } + } + } + return cache; + } + + /** + * Create a new ConcurrentMapCache instance for the specified cache name. + * @param name the name of the cache + * @return the ConcurrentMapCache (or a decorator thereof) + */ + protected Cache createConcurrentMapCache(String name) { + return new ConcurrentMapCache(name); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/package-info.java b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/package-info.java index 4965e8534d0..c322897233a 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/concurrent/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/concurrent/package-info.java @@ -1,10 +1,9 @@ - -/** - * - * Implementation package for java.util.concurrent based - * caches. Provides a CacheManager and Cache implementation - * for usage in a Spring context. - * - */ -package org.springframework.cache.concurrent; - + +/** + * Implementation package for {@code java.util.concurrent} based caches. + * Provides a {@link org.springframework.cache.CacheManager CacheManager} + * and {@link org.springframework.cache.Cache Cache} implementation for + * use in a Spring context. + */ +package org.springframework.cache.concurrent; + 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 525b317f3c0..26a736dd41e 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 @@ -1,142 +1,143 @@ -/* - * Copyright 2002-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.config; - -import static org.springframework.context.annotation.AnnotationConfigUtils.*; - -import org.springframework.aop.config.AopNamespaceUtils; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -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.AnnotationCacheOperationSource; -import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor; -import org.springframework.cache.interceptor.CacheInterceptor; -import org.w3c.dom.Element; - -/** - * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} - * implementation that allows users to easily configure all the infrastructure - * beans required to enable annotation-driven cache demarcation. - * - *

By default, all proxies are created as JDK proxies. This may cause some - * problems if you are injecting objects as concrete classes rather than - * interfaces. To overcome this restriction you can set the - * 'proxy-target-class' attribute to 'true', which - * will result in class-based proxies being created. - * - * @author Costin Leau - * @since 3.1 - */ -class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser { - - /** - * Parses the '<cache:annotation-driven/>' tag. Will - * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator} - * with the container as necessary. - */ - public BeanDefinition parse(Element element, ParserContext parserContext) { - String mode = element.getAttribute("mode"); - if ("aspectj".equals(mode)) { - // mode="aspectj" - registerCacheAspect(element, parserContext); - } - else { - // mode="proxy" - AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); - } - - return null; - } - - private static void parseCacheManagerProperty(Element element, BeanDefinition def) { - def.getPropertyValues().add("cacheManager", - new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element))); - } - - /** - * Registers a - *

-	 * 
-	 *   
-	 * 
-	 *
-	 * 
- * @param element - * @param parserContext - */ - private void registerCacheAspect(Element element, ParserContext parserContext) { - if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ASPECT_BEAN_NAME)) { - RootBeanDefinition def = new RootBeanDefinition(); - def.setBeanClassName(CACHE_ASPECT_CLASS_NAME); - def.setFactoryMethodName("aspectOf"); - parseCacheManagerProperty(element, def); - parserContext.registerBeanComponent(new BeanComponentDefinition(def, CACHE_ASPECT_BEAN_NAME)); - } - } - - - /** - * Inner class to just introduce an AOP framework dependency when actually in proxy mode. - */ - private static class AopAutoProxyConfigurer { - - public static void configureAutoProxyCreator(Element element, ParserContext parserContext) { - AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); - - if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) { - Object eleSource = parserContext.extractSource(element); - - // Create the CacheOperationSource definition. - RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class); - sourceDef.setSource(eleSource); - sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef); - - // Create the CacheInterceptor definition. - RootBeanDefinition interceptorDef = new RootBeanDefinition(CacheInterceptor.class); - interceptorDef.setSource(eleSource); - interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - parseCacheManagerProperty(element, interceptorDef); - CacheNamespaceHandler.parseKeyGenerator(element, interceptorDef); - interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName)); - String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); - - // Create the CacheAdvisor definition. - RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class); - advisorDef.setSource(eleSource); - advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName)); - advisorDef.getPropertyValues().add("adviceBeanName", interceptorName); - if (element.hasAttribute("order")) { - advisorDef.getPropertyValues().add("order", element.getAttribute("order")); - } - parserContext.getRegistry().registerBeanDefinition(CACHE_ADVISOR_BEAN_NAME, advisorDef); - - CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), - eleSource); - compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName)); - compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName)); - compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, CACHE_ADVISOR_BEAN_NAME)); - parserContext.registerComponent(compositeDef); - } - } - } -} \ No newline at end of file +/* + * Copyright 2002-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.config; + +import static org.springframework.context.annotation.AnnotationConfigUtils.*; + +import org.springframework.aop.config.AopNamespaceUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +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.AnnotationCacheOperationSource; +import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor; +import org.springframework.cache.interceptor.CacheInterceptor; +import org.w3c.dom.Element; + +/** + * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} + * implementation that allows users to easily configure all the + * infrastructure beans required to enable annotation-driven cache + * demarcation. + * + *

By default, all proxies are created as JDK proxies. This may cause + * some problems if you are injecting objects as concrete classes rather + * than interfaces. To overcome this restriction you can set the + * '{@code proxy-target-class}' attribute to '{@code true}', which will + * result in class-based proxies being created. + * + * @author Costin Leau + * @since 3.1 + */ +class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser { + + /** + * Parses the '{@code }' tag. Will + * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary + * register an AutoProxyCreator} with the container as necessary. + */ + public BeanDefinition parse(Element element, ParserContext parserContext) { + String mode = element.getAttribute("mode"); + if ("aspectj".equals(mode)) { + // mode="aspectj" + registerCacheAspect(element, parserContext); + } + else { + // mode="proxy" + AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); + } + + return null; + } + + private static void parseCacheManagerProperty(Element element, BeanDefinition def) { + def.getPropertyValues().add("cacheManager", + new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element))); + } + + /** + * Registers a + *

+	 * 
+	 *   
+	 * 
+	 *
+	 * 
+ * @param element + * @param parserContext + */ + private void registerCacheAspect(Element element, ParserContext parserContext) { + if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ASPECT_BEAN_NAME)) { + RootBeanDefinition def = new RootBeanDefinition(); + def.setBeanClassName(CACHE_ASPECT_CLASS_NAME); + def.setFactoryMethodName("aspectOf"); + parseCacheManagerProperty(element, def); + parserContext.registerBeanComponent(new BeanComponentDefinition(def, CACHE_ASPECT_BEAN_NAME)); + } + } + + + /** + * Inner class to just introduce an AOP framework dependency when actually in proxy mode. + */ + private static class AopAutoProxyConfigurer { + + public static void configureAutoProxyCreator(Element element, ParserContext parserContext) { + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); + + if (!parserContext.getRegistry().containsBeanDefinition(CACHE_ADVISOR_BEAN_NAME)) { + Object eleSource = parserContext.extractSource(element); + + // Create the CacheOperationSource definition. + RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationCacheOperationSource.class); + sourceDef.setSource(eleSource); + sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef); + + // Create the CacheInterceptor definition. + RootBeanDefinition interceptorDef = new RootBeanDefinition(CacheInterceptor.class); + interceptorDef.setSource(eleSource); + interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parseCacheManagerProperty(element, interceptorDef); + CacheNamespaceHandler.parseKeyGenerator(element, interceptorDef); + interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName)); + String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); + + // Create the CacheAdvisor definition. + RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class); + advisorDef.setSource(eleSource); + advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName)); + advisorDef.getPropertyValues().add("adviceBeanName", interceptorName); + if (element.hasAttribute("order")) { + advisorDef.getPropertyValues().add("order", element.getAttribute("order")); + } + parserContext.getRegistry().registerBeanDefinition(CACHE_ADVISOR_BEAN_NAME, advisorDef); + + CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), + eleSource); + compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName)); + compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName)); + compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, CACHE_ADVISOR_BEAN_NAME)); + parserContext.registerComponent(compositeDef); + } + } + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java b/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java index 5150169cc19..1b033832096 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java @@ -1,216 +1,215 @@ -/* - * 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.config; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.springframework.beans.factory.config.TypedStringValue; -import org.springframework.beans.factory.parsing.ReaderContext; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.cache.annotation.AnnotationCacheOperationSource; -import org.springframework.cache.interceptor.CacheEvictOperation; -import org.springframework.cache.interceptor.CacheInterceptor; -import org.springframework.cache.interceptor.CacheOperation; -import org.springframework.cache.interceptor.CachePutOperation; -import org.springframework.cache.interceptor.CacheableOperation; -import org.springframework.cache.interceptor.NameMatchCacheOperationSource; -import org.springframework.util.StringUtils; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; - -/** - * {@link org.springframework.beans.factory.xml.BeanDefinitionParser - * BeanDefinitionParser} for the {@code } tag. - * - * @author Costin Leau - * - */ -class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { - - /** - * Simple, reusable class used for overriding defaults. - * - * @author Costin Leau - */ - private static class Props { - - private String key, condition, method; - private String[] caches = null; - - Props(Element root) { - String defaultCache = root.getAttribute("cache"); - key = root.getAttribute("key"); - condition = root.getAttribute("condition"); - method = root.getAttribute(METHOD_ATTRIBUTE); - - if (StringUtils.hasText(defaultCache)) { - caches = StringUtils.commaDelimitedListToStringArray(defaultCache.trim()); - } - } - - CacheOperation merge(Element element, ReaderContext readerCtx, CacheOperation op) { - String cache = element.getAttribute("cache"); - String k = element.getAttribute("key"); - String c = element.getAttribute("condition"); - - String[] localCaches = caches; - String localKey = key, localCondition = condition; - - // sanity check - if (StringUtils.hasText(cache)) { - localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim()); - } else { - if (caches == null) { - readerCtx.error("No cache specified specified for " + element.getNodeName(), element); - } - } - - if (StringUtils.hasText(k)) { - localKey = k.trim(); - } - - if (StringUtils.hasText(c)) { - localCondition = c.trim(); - } - op.setCacheNames(localCaches); - op.setKey(localKey); - op.setCondition(localCondition); - - return op; - } - - String merge(Element element, ReaderContext readerCtx) { - String m = element.getAttribute(METHOD_ATTRIBUTE); - - if (StringUtils.hasText(m)) { - return m.trim(); - } - if (StringUtils.hasText(method)) { - return method; - } - readerCtx.error("No method specified for " + element.getNodeName(), element); - return null; - } - } - - private static final String CACHEABLE_ELEMENT = "cacheable"; - private static final String CACHE_EVICT_ELEMENT = "cache-evict"; - private static final String CACHE_PUT_ELEMENT = "cache-put"; - private static final String METHOD_ATTRIBUTE = "method"; - private static final String DEFS_ELEMENT = "definitions"; - - @Override - protected Class getBeanClass(Element element) { - return CacheInterceptor.class; - } - - @Override - protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element)); - CacheNamespaceHandler.parseKeyGenerator(element, builder.getBeanDefinition()); - - List cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT); - if (cacheDefs.size() >= 1) { - // Using attributes source. - List attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext); - builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions); - } else { - // Assume annotations source. - builder.addPropertyValue("cacheOperationSources", new RootBeanDefinition( - AnnotationCacheOperationSource.class)); - } - } - - private List parseDefinitionsSources(List definitions, ParserContext parserContext) { - ManagedList defs = new ManagedList(definitions.size()); - - // extract default param for the definition - for (Element element : definitions) { - defs.add(parseDefinitionSource(element, parserContext)); - } - - return defs; - } - - private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) { - Props prop = new Props(definition); - // add cacheable first - - ManagedMap> cacheOpMap = new ManagedMap>(); - cacheOpMap.setSource(parserContext.extractSource(definition)); - - List cacheableCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT); - - for (Element opElement : cacheableCacheMethods) { - String name = prop.merge(opElement, parserContext.getReaderContext()); - TypedStringValue nameHolder = new TypedStringValue(name); - nameHolder.setSource(parserContext.extractSource(opElement)); - CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation()); - - Collection col = cacheOpMap.get(nameHolder); - if (col == null) { - col = new ArrayList(2); - cacheOpMap.put(nameHolder, col); - } - col.add(op); - } - - List evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT); - - for (Element opElement : evictCacheMethods) { - String name = prop.merge(opElement, parserContext.getReaderContext()); - TypedStringValue nameHolder = new TypedStringValue(name); - nameHolder.setSource(parserContext.extractSource(opElement)); - CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation()); - - Collection col = cacheOpMap.get(nameHolder); - if (col == null) { - col = new ArrayList(2); - cacheOpMap.put(nameHolder, col); - } - col.add(op); - } - - List putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT); - - for (Element opElement : putCacheMethods) { - String name = prop.merge(opElement, parserContext.getReaderContext()); - TypedStringValue nameHolder = new TypedStringValue(name); - nameHolder.setSource(parserContext.extractSource(opElement)); - CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation()); - - Collection col = cacheOpMap.get(nameHolder); - if (col == null) { - col = new ArrayList(2); - cacheOpMap.put(nameHolder, col); - } - col.add(op); - } - - RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class); - attributeSourceDefinition.setSource(parserContext.extractSource(definition)); - attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpMap); - return attributeSourceDefinition; - } -} \ No newline at end of file +/* + * 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.config; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.parsing.ReaderContext; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.cache.annotation.AnnotationCacheOperationSource; +import org.springframework.cache.interceptor.CacheEvictOperation; +import org.springframework.cache.interceptor.CacheInterceptor; +import org.springframework.cache.interceptor.CacheOperation; +import org.springframework.cache.interceptor.CachePutOperation; +import org.springframework.cache.interceptor.CacheableOperation; +import org.springframework.cache.interceptor.NameMatchCacheOperationSource; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * {@link org.springframework.beans.factory.xml.BeanDefinitionParser + * BeanDefinitionParser} for the {@code } tag. + * + * @author Costin Leau + */ +class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { + + /** + * Simple, reusable class used for overriding defaults. + * + * @author Costin Leau + */ + private static class Props { + + private String key, condition, method; + private String[] caches = null; + + Props(Element root) { + String defaultCache = root.getAttribute("cache"); + key = root.getAttribute("key"); + condition = root.getAttribute("condition"); + method = root.getAttribute(METHOD_ATTRIBUTE); + + if (StringUtils.hasText(defaultCache)) { + caches = StringUtils.commaDelimitedListToStringArray(defaultCache.trim()); + } + } + + CacheOperation merge(Element element, ReaderContext readerCtx, CacheOperation op) { + String cache = element.getAttribute("cache"); + String k = element.getAttribute("key"); + String c = element.getAttribute("condition"); + + String[] localCaches = caches; + String localKey = key, localCondition = condition; + + // sanity check + if (StringUtils.hasText(cache)) { + localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim()); + } else { + if (caches == null) { + readerCtx.error("No cache specified specified for " + element.getNodeName(), element); + } + } + + if (StringUtils.hasText(k)) { + localKey = k.trim(); + } + + if (StringUtils.hasText(c)) { + localCondition = c.trim(); + } + op.setCacheNames(localCaches); + op.setKey(localKey); + op.setCondition(localCondition); + + return op; + } + + String merge(Element element, ReaderContext readerCtx) { + String m = element.getAttribute(METHOD_ATTRIBUTE); + + if (StringUtils.hasText(m)) { + return m.trim(); + } + if (StringUtils.hasText(method)) { + return method; + } + readerCtx.error("No method specified for " + element.getNodeName(), element); + return null; + } + } + + private static final String CACHEABLE_ELEMENT = "cacheable"; + private static final String CACHE_EVICT_ELEMENT = "cache-evict"; + private static final String CACHE_PUT_ELEMENT = "cache-put"; + private static final String METHOD_ATTRIBUTE = "method"; + private static final String DEFS_ELEMENT = "definitions"; + + @Override + protected Class getBeanClass(Element element) { + return CacheInterceptor.class; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element)); + CacheNamespaceHandler.parseKeyGenerator(element, builder.getBeanDefinition()); + + List cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT); + if (cacheDefs.size() >= 1) { + // Using attributes source. + List attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext); + builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions); + } else { + // Assume annotations source. + builder.addPropertyValue("cacheOperationSources", new RootBeanDefinition( + AnnotationCacheOperationSource.class)); + } + } + + private List parseDefinitionsSources(List definitions, ParserContext parserContext) { + ManagedList defs = new ManagedList(definitions.size()); + + // extract default param for the definition + for (Element element : definitions) { + defs.add(parseDefinitionSource(element, parserContext)); + } + + return defs; + } + + private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) { + Props prop = new Props(definition); + // add cacheable first + + ManagedMap> cacheOpMap = new ManagedMap>(); + cacheOpMap.setSource(parserContext.extractSource(definition)); + + List cacheableCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT); + + for (Element opElement : cacheableCacheMethods) { + String name = prop.merge(opElement, parserContext.getReaderContext()); + TypedStringValue nameHolder = new TypedStringValue(name); + nameHolder.setSource(parserContext.extractSource(opElement)); + CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation()); + + Collection col = cacheOpMap.get(nameHolder); + if (col == null) { + col = new ArrayList(2); + cacheOpMap.put(nameHolder, col); + } + col.add(op); + } + + List evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT); + + for (Element opElement : evictCacheMethods) { + String name = prop.merge(opElement, parserContext.getReaderContext()); + TypedStringValue nameHolder = new TypedStringValue(name); + nameHolder.setSource(parserContext.extractSource(opElement)); + CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation()); + + Collection col = cacheOpMap.get(nameHolder); + if (col == null) { + col = new ArrayList(2); + cacheOpMap.put(nameHolder, col); + } + col.add(op); + } + + List putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT); + + for (Element opElement : putCacheMethods) { + String name = prop.merge(opElement, parserContext.getReaderContext()); + TypedStringValue nameHolder = new TypedStringValue(name); + nameHolder.setSource(parserContext.extractSource(opElement)); + CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation()); + + Collection col = cacheOpMap.get(nameHolder); + if (col == null) { + col = new ArrayList(2); + cacheOpMap.put(nameHolder, col); + } + col.add(op); + } + + RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class); + attributeSourceDefinition.setSource(parserContext.extractSource(definition)); + attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpMap); + return attributeSourceDefinition; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/config/CacheNamespaceHandler.java b/org.springframework.context/src/main/java/org/springframework/cache/config/CacheNamespaceHandler.java index cf94fef85a2..40100245f35 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/config/CacheNamespaceHandler.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/config/CacheNamespaceHandler.java @@ -1,58 +1,58 @@ -/* - * Copyright 2002-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.config; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * NamespaceHandler allowing for the configuration of - * declarative cache management using either XML or using annotations. - * - *

This namespace handler is the central piece of functionality in the - * Spring cache management facilities. - * - * @author Costin Leau - * @since 3.1 - */ -public class CacheNamespaceHandler extends NamespaceHandlerSupport { - - static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager"; - static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager"; - - static String extractCacheManager(Element element) { - return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ? element - .getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) - : CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME); - } - - static BeanDefinition parseKeyGenerator(Element element, BeanDefinition def) { - String name = element.getAttribute("key-generator"); - if (StringUtils.hasText(name)) { - def.getPropertyValues().add("keyGenerator", new RuntimeBeanReference(name.trim())); - } - return def; - } - - public void init() { - registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser()); - registerBeanDefinitionParser("advice", new CacheAdviceParser()); - } -} +/* + * Copyright 2002-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.config; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * {@code NamespaceHandler} allowing for the configuration of declarative + * cache management using either XML or using annotations. + * + *

This namespace handler is the central piece of functionality in the + * Spring cache management facilities. + * + * @author Costin Leau + * @since 3.1 + */ +public class CacheNamespaceHandler extends NamespaceHandlerSupport { + + static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager"; + static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager"; + + static String extractCacheManager(Element element) { + return (element.hasAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) ? element + .getAttribute(CacheNamespaceHandler.CACHE_MANAGER_ATTRIBUTE) + : CacheNamespaceHandler.DEFAULT_CACHE_MANAGER_BEAN_NAME); + } + + static BeanDefinition parseKeyGenerator(Element element, BeanDefinition def) { + String name = element.getAttribute("key-generator"); + if (StringUtils.hasText(name)) { + def.getPropertyValues().add("keyGenerator", new RuntimeBeanReference(name.trim())); + } + return def; + } + + public void init() { + registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser()); + registerBeanDefinitionParser("advice", new CacheAdviceParser()); + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/config/package-info.java b/org.springframework.context/src/main/java/org/springframework/cache/config/package-info.java index e601fd4b73c..4e44ffa83ed 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/config/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/config/package-info.java @@ -1,9 +1,8 @@ - -/** - * - * Support package for declarative caching configuration, - * with XML schema being the primary configuration format. - * - */ -package org.springframework.cache.config; - + +/** + * Support package for declarative caching configuration, with XML + * schema being the primary configuration format. See {@link + * org.springframework.cache.annotation.EnableCaching EnableCaching} + * for details on code-based configuration without XML. + */ +package org.springframework.cache.config; 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 21d1d822c82..b513e56ff4b 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 @@ -1,77 +1,77 @@ -/* - * Copyright 2002-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.ehcache; - -import net.sf.ehcache.Ehcache; -import net.sf.ehcache.Element; -import net.sf.ehcache.Status; - -import org.springframework.cache.Cache; -import org.springframework.cache.support.ValueWrapperImpl; -import org.springframework.util.Assert; - -/** - * {@link Cache} implementation on top of an {@link Ehcache} instance. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -public class EhCacheCache implements Cache { - - private final Ehcache cache; - - - /** - * Create an {@link EhCacheCache} instance. - * @param ehcache backing Ehcache instance - */ - public EhCacheCache(Ehcache ehcache) { - Assert.notNull(ehcache, "Ehcache must not be null"); - Status status = ehcache.getStatus(); - Assert.isTrue(Status.STATUS_ALIVE.equals(status), - "An 'alive' Ehcache is required - current cache is " + status.toString()); - this.cache = ehcache; - } - - - public String getName() { - return this.cache.getName(); - } - - public Ehcache getNativeCache() { - return this.cache; - } - - public void clear() { - this.cache.removeAll(); - } - - public ValueWrapper get(Object key) { - Element element = this.cache.get(key); - return (element != null ? new ValueWrapperImpl(element.getObjectValue()) : null); - } - - public void put(Object key, Object value) { - this.cache.put(new Element(key, value)); - } - - public void evict(Object key) { - this.cache.remove(key); - } - -} +/* + * Copyright 2002-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.ehcache; + +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.Element; +import net.sf.ehcache.Status; + +import org.springframework.cache.Cache; +import org.springframework.cache.support.ValueWrapperImpl; +import org.springframework.util.Assert; + +/** + * {@link Cache} implementation on top of an {@link Ehcache} instance. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +public class EhCacheCache implements Cache { + + private final Ehcache cache; + + + /** + * Create an {@link EhCacheCache} instance. + * @param ehcache backing Ehcache instance + */ + public EhCacheCache(Ehcache ehcache) { + Assert.notNull(ehcache, "Ehcache must not be null"); + Status status = ehcache.getStatus(); + Assert.isTrue(Status.STATUS_ALIVE.equals(status), + "An 'alive' Ehcache is required - current cache is " + status.toString()); + this.cache = ehcache; + } + + + public String getName() { + return this.cache.getName(); + } + + public Ehcache getNativeCache() { + return this.cache; + } + + public void clear() { + this.cache.removeAll(); + } + + public ValueWrapper get(Object key) { + Element element = this.cache.get(key); + return (element != null ? new ValueWrapperImpl(element.getObjectValue()) : null); + } + + public void put(Object key, Object value) { + this.cache.put(new Element(key, value)); + } + + public void evict(Object key) { + this.cache.remove(key); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java index 65969a36931..2004597ef73 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java @@ -1,79 +1,79 @@ -/* - * Copyright 2002-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.ehcache; - -import java.util.Collection; -import java.util.LinkedHashSet; - -import net.sf.ehcache.Ehcache; -import net.sf.ehcache.Status; - -import org.springframework.cache.Cache; -import org.springframework.cache.support.AbstractCacheManager; -import org.springframework.util.Assert; - -/** - * CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -public class EhCacheCacheManager extends AbstractCacheManager { - - private net.sf.ehcache.CacheManager cacheManager; - - - /** - * Set the backing EhCache {@link net.sf.ehcache.CacheManager}. - */ - public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) { - this.cacheManager = cacheManager; - } - - - @Override - protected Collection loadCaches() { - Assert.notNull(this.cacheManager, "A backing EhCache CacheManager is required"); - Status status = this.cacheManager.getStatus(); - Assert.isTrue(Status.STATUS_ALIVE.equals(status), - "An 'alive' EhCache CacheManager is required - current cache is " + status.toString()); - - String[] names = this.cacheManager.getCacheNames(); - Collection caches = new LinkedHashSet(names.length); - for (String name : names) { - caches.add(new EhCacheCache(this.cacheManager.getEhcache(name))); - } - return caches; - } - - @Override - public Cache getCache(String name) { - Cache cache = super.getCache(name); - if (cache == null) { - // check the EhCache cache again - // (in case the cache was added at runtime) - Ehcache ehcache = this.cacheManager.getEhcache(name); - if (ehcache != null) { - cache = new EhCacheCache(ehcache); - addCache(cache); - } - } - return cache; - } - -} +/* + * Copyright 2002-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.ehcache; + +import java.util.Collection; +import java.util.LinkedHashSet; + +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.Status; + +import org.springframework.cache.Cache; +import org.springframework.cache.support.AbstractCacheManager; +import org.springframework.util.Assert; + +/** + * CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +public class EhCacheCacheManager extends AbstractCacheManager { + + private net.sf.ehcache.CacheManager cacheManager; + + + /** + * Set the backing EhCache {@link net.sf.ehcache.CacheManager}. + */ + public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + + @Override + protected Collection loadCaches() { + Assert.notNull(this.cacheManager, "A backing EhCache CacheManager is required"); + Status status = this.cacheManager.getStatus(); + Assert.isTrue(Status.STATUS_ALIVE.equals(status), + "An 'alive' EhCache CacheManager is required - current cache is " + status.toString()); + + String[] names = this.cacheManager.getCacheNames(); + Collection caches = new LinkedHashSet(names.length); + for (String name : names) { + caches.add(new EhCacheCache(this.cacheManager.getEhcache(name))); + } + return caches; + } + + @Override + public Cache getCache(String name) { + Cache cache = super.getCache(name); + if (cache == null) { + // check the EhCache cache again + // (in case the cache was added at runtime) + Ehcache ehcache = this.cacheManager.getEhcache(name); + if (ehcache != null) { + cache = new EhCacheCache(ehcache); + addCache(cache); + } + } + return cache; + } + +} 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 index 3d8568c9303..bd4de539f14 100644 --- 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 @@ -1,218 +1,221 @@ -/* - * Copyright 2002-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.Collection; -import java.util.Collections; -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 - * @since 3.1 - */ -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 Collection NULL_CACHING_ATTRIBUTE = Collections.emptyList(); - - /** - * 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 Collection getCacheOperations(Method method, Class targetClass) { - // First, see if we have a cached value. - Object cacheKey = getCacheKey(method, targetClass); - Collection 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. - Collection cacheDefs = computeCacheOperationDefinition(method, targetClass); - // Put it in the cache. - if (cacheDefs == null) { - this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE); - } - else { - if (logger.isDebugEnabled()) { - logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheDefs); - } - this.attributeCache.put(cacheKey, cacheDefs); - } - return cacheDefs; - } - } - - /** - * 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); - } - - private Collection 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. - Collection opDef = findCacheOperations(specificMethod); - if (opDef != null) { - return opDef; - } - - // Second try is the caching operation on the target class. - opDef = findCacheOperations(specificMethod.getDeclaringClass()); - if (opDef != null) { - return opDef; - } - - if (specificMethod != method) { - // Fall back is to look at the original method. - opDef = findCacheOperations(method); - if (opDef != null) { - return opDef; - } - // Last fall back is the class of the original method. - return findCacheOperations(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 Collection findCacheOperations(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 Collection findCacheOperations(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 CacheOperation 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 +/* + * Copyright 2002-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.Collection; +import java.util.Collections; +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 + * @since 3.1 + */ +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 Collection NULL_CACHING_ATTRIBUTE = Collections.emptyList(); + + /** + * 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 {@code null}) + * @param targetClass the target class for this invocation (may be {@code null}) + * @return {@link CacheOperation} for this method, or {@code null} if the method + * is not cacheable + */ + public Collection getCacheOperations(Method method, Class targetClass) { + // First, see if we have a cached value. + Object cacheKey = getCacheKey(method, targetClass); + Collection 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. + Collection cacheDefs = computeCacheOperationDefinition(method, targetClass); + // Put it in the cache. + if (cacheDefs == null) { + this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE); + } + else { + if (logger.isDebugEnabled()) { + logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheDefs); + } + this.attributeCache.put(cacheKey, cacheDefs); + } + return cacheDefs; + } + } + + /** + * 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 {@code null}) + * @param targetClass the target class (may be {@code null}) + * @return the cache key (never {@code null}) + */ + protected Object getCacheKey(Method method, Class targetClass) { + return new DefaultCacheKey(method, targetClass); + } + + private Collection 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. + Collection opDef = findCacheOperations(specificMethod); + if (opDef != null) { + return opDef; + } + + // Second try is the caching operation on the target class. + opDef = findCacheOperations(specificMethod.getDeclaringClass()); + if (opDef != null) { + return opDef; + } + + if (specificMethod != method) { + // Fall back is to look at the original method. + opDef = findCacheOperations(method); + if (opDef != null) { + return opDef; + } + // Last fall back is the class of the original method. + return findCacheOperations(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 {@code null} if none) + */ + protected abstract Collection findCacheOperations(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 {@code null} if none) + */ + protected abstract Collection findCacheOperations(Class clazz); + + /** + * Should only public methods be allowed to have caching semantics? + *

The default implementation returns {@code false}. + */ + protected boolean allowPublicMethodsOnly() { + return false; + } + + + /** + * Default cache key for the CacheOperation 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); + } + } +} 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 index 9e51071f4c7..97cb34d624b 100644 --- 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 @@ -1,65 +1,65 @@ -/* - * Copyright 2002-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 - * @since 3.1 - */ -@SuppressWarnings("serial") -public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { - - private CacheOperationSource cacheOperationSource; - - private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() { - @Override - protected CacheOperationSource getCacheOperationSource() { - return cacheOperationSource; - } - }; - - - /** - * 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 setCacheOperationSource(CacheOperationSource cacheOperationSource) { - this.cacheOperationSource = cacheOperationSource; - } - - /** - * 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; - } - -} +/* + * Copyright 2002-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 + * @since 3.1 + */ +@SuppressWarnings("serial") +public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { + + private CacheOperationSource cacheOperationSource; + + private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() { + @Override + protected CacheOperationSource getCacheOperationSource() { + return cacheOperationSource; + } + }; + + + /** + * 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 setCacheOperationSource(CacheOperationSource cacheOperationSource) { + this.cacheOperationSource = cacheOperationSource; + } + + /** + * 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; + } + +} 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 c1b7e703903..8fcaeab717b 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 @@ -1,463 +1,465 @@ -/* - * Copyright 2002-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.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.aop.framework.AopProxyUtils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; -import org.springframework.expression.EvaluationContext; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -/** - * Base class for caching aspects, such as the {@link CacheInterceptor} - * or an AspectJ aspect. - * - *

This enables the underlying Spring caching infrastructure to be used easily - * to implement an aspect for any aspect system. - * - *

Subclasses are responsible for calling methods in this class in the correct order. - * - *

Uses the Strategy design pattern. A {@link CacheManager} implementation will - * perform the actual cache management, and a {@link CacheOperationSource} is used for - * determining caching operation definitions. - * - *

A cache aspect is serializable if its {@code CacheManager} and - * {@code CacheOperationSource} are serializable. - * - * @author Costin Leau - * @author Juergen Hoeller - * @author Chris Beams - * @since 3.1 - */ -public abstract class CacheAspectSupport implements InitializingBean { - - public interface Invoker { - Object invoke(); - } - - protected final Log logger = LogFactory.getLog(getClass()); - - private CacheManager cacheManager; - - private CacheOperationSource cacheOperationSource; - - private final ExpressionEvaluator evaluator = new ExpressionEvaluator(); - - private KeyGenerator keyGenerator = new DefaultKeyGenerator(); - - private boolean initialized = false; - - private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict"; - - /** - * Set the CacheManager that this cache aspect should delegate to. - */ - public void setCacheManager(CacheManager cacheManager) { - this.cacheManager = cacheManager; - } - - /** - * Return the CacheManager that this cache aspect delegates to. - */ - public CacheManager getCacheManager() { - return this.cacheManager; - } - - /** - * Set one or more cache definition sources which are used to find the cache - * attributes. If more than one source is provided, they will be aggregated using a - * {@link CompositeCacheOperationSource}. - * @param cacheOperationSources must not be {@code null} - */ - public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) { - Assert.notEmpty(cacheOperationSources); - this.cacheOperationSource = - (cacheOperationSources.length > 1 ? - new CompositeCacheOperationSource(cacheOperationSources) : - cacheOperationSources[0]); - } - - /** - * Return the CacheOperationSource for this cache aspect. - */ - public CacheOperationSource getCacheOperationSource() { - return this.cacheOperationSource; - } - - /** - * Set the KeyGenerator for this cache aspect. - * Default is {@link DefaultKeyGenerator}. - */ - public void setKeyGenerator(KeyGenerator keyGenerator) { - this.keyGenerator = keyGenerator; - } - - /** - * Return the KeyGenerator for this cache aspect, - */ - public KeyGenerator getKeyGenerator() { - return this.keyGenerator; - } - - public void afterPropertiesSet() { - if (this.cacheManager == null) { - throw new IllegalStateException("'cacheManager' is required"); - } - if (this.cacheOperationSource == null) { - throw new IllegalStateException("Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: " - + "If there are no cacheable methods, then don't use a cache aspect."); - } - - this.initialized = true; - } - - /** - * Convenience method to return a String representation of this Method - * for use in logging. Can be overridden in subclasses to provide a - * different identifier for the given method. - * @param method the method we're interested in - * @param targetClass class the method is on - * @return log message identifying this method - * @see org.springframework.util.ClassUtils#getQualifiedMethodName - */ - protected String methodIdentification(Method method, Class targetClass) { - Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); - return ClassUtils.getQualifiedMethodName(specificMethod); - } - - protected Collection getCaches(CacheOperation operation) { - Set cacheNames = operation.getCacheNames(); - Collection caches = new ArrayList(cacheNames.size()); - for (String cacheName : cacheNames) { - Cache cache = this.cacheManager.getCache(cacheName); - if (cache == null) { - throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation); - } - caches.add(cache); - } - return caches; - } - - protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args, - Object target, Class targetClass) { - - return new CacheOperationContext(operation, method, args, target, targetClass); - } - - protected Object execute(Invoker invoker, Object target, Method method, Object[] args) { - // check whether aspect is enabled - // to cope with cases where the AJ is pulled in automatically - if (!this.initialized) { - return invoker.invoke(); - } - - // get backing class - Class targetClass = AopProxyUtils.ultimateTargetClass(target); - if (targetClass == null && target != null) { - targetClass = target.getClass(); - } - final Collection cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass); - - // analyze caching information - if (!CollectionUtils.isEmpty(cacheOp)) { - Map> ops = createOperationContext(cacheOp, method, args, target, - targetClass); - - // start with evictions - inspectCacheEvicts(ops.get(EVICT)); - - // follow up with cacheable - CacheStatus status = inspectCacheables(ops.get(CACHEABLE)); - - Object retVal = null; - Map updates = inspectCacheUpdates(ops.get(UPDATE)); - - if (status != null) { - if (status.updateRequired) { - updates.putAll(status.cUpdates); - } - // return cached object - else { - return status.retVal; - } - } - - retVal = invoker.invoke(); - - if (!updates.isEmpty()) { - update(updates, retVal); - } - - return retVal; - } - - return invoker.invoke(); - } - - private void inspectCacheEvicts(Collection evictions) { - - if (!evictions.isEmpty()) { - - boolean log = logger.isTraceEnabled(); - - for (CacheOperationContext context : evictions) { - if (context.isConditionPassing()) { - CacheEvictOperation evictOp = (CacheEvictOperation) context.operation; - - // for each cache - // lazy key initialization - Object key = null; - - for (Cache cache : context.getCaches()) { - // cache-wide flush - if (evictOp.isCacheWide()) { - cache.clear(); - if (log) { - logger.trace("Invalidating entire cache for definition " + evictOp + " on method " + context.method); - } - } else { - // check key - if (key == null) { - key = context.generateKey(); - } - if (log) { - logger.trace("Invalidating cache key " + key + " for definition " + evictOp + " on method " + context.method); - } - cache.evict(key); - } - } - } - else { - if (log) { - logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation); - } - } - } - } - } - - private CacheStatus inspectCacheables(Collection cacheables) { - Map cUpdates = new LinkedHashMap( - cacheables.size()); - - boolean updateRequire = false; - Object retVal = null; - - if (!cacheables.isEmpty()) { - boolean log = logger.isTraceEnabled(); - boolean atLeastOnePassed = false; - - for (CacheOperationContext context : cacheables) { - if (context.isConditionPassing()) { - atLeastOnePassed = true; - Object key = context.generateKey(); - - if (log) { - logger.trace("Computed cache key " + key + " for definition " + context.operation); - } - if (key == null) { - throw new IllegalArgumentException( - "Null key returned for cache definition (maybe you are using named params on classes without debug info?) " - + context.operation); - } - - // add op/key (in case an update is discovered later on) - cUpdates.put(context, key); - - boolean localCacheHit = false; - - // check whether the cache needs to be inspected or not (the method will be invoked anyway) - if (!updateRequire) { - for (Cache cache : context.getCaches()) { - Cache.ValueWrapper wrapper = cache.get(key); - if (wrapper != null) { - retVal = wrapper.get(); - localCacheHit = true; - break; - } - } - } - - if (!localCacheHit) { - updateRequire = true; - } - } - else { - if (log) { - logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation); - } - } - } - - // return a status only if at least on cacheable matched - if (atLeastOnePassed) { - return new CacheStatus(cUpdates, updateRequire, retVal); - } - } - - return null; - } - - private static class CacheStatus { - // caches/key - final Map cUpdates; - final boolean updateRequired; - final Object retVal; - - CacheStatus(Map cUpdates, boolean updateRequired, Object retVal) { - this.cUpdates = cUpdates; - this.updateRequired = updateRequired; - this.retVal = retVal; - } - } - - private Map inspectCacheUpdates(Collection updates) { - - Map cUpdates = new LinkedHashMap(updates.size()); - - if (!updates.isEmpty()) { - boolean log = logger.isTraceEnabled(); - - for (CacheOperationContext context : updates) { - if (context.isConditionPassing()) { - - Object key = context.generateKey(); - - if (log) { - logger.trace("Computed cache key " + key + " for definition " + context.operation); - } - if (key == null) { - throw new IllegalArgumentException( - "Null key returned for cache definition (maybe you are using named params on classes without debug info?) " - + context.operation); - } - - // add op/key (in case an update is discovered later on) - cUpdates.put(context, key); - } - else { - if (log) { - logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation); - } - } - } - } - - return cUpdates; - } - - private void update(Map updates, Object retVal) { - for (Map.Entry entry : updates.entrySet()) { - for (Cache cache : entry.getKey().getCaches()) { - cache.put(entry.getValue(), retVal); - } - } - } - - private Map> createOperationContext(Collection cacheOp, - Method method, Object[] args, Object target, Class targetClass) { - Map> map = new LinkedHashMap>(3); - - Collection cacheables = new ArrayList(); - Collection evicts = new ArrayList(); - Collection updates = new ArrayList(); - - for (CacheOperation cacheOperation : cacheOp) { - CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass); - - if (cacheOperation instanceof CacheableOperation) { - cacheables.add(opContext); - } - - if (cacheOperation instanceof CacheEvictOperation) { - evicts.add(opContext); - } - - if (cacheOperation instanceof CachePutOperation) { - updates.add(opContext); - } - } - - map.put(CACHEABLE, cacheables); - map.put(EVICT, evicts); - map.put(UPDATE, updates); - - return map; - } - - protected class CacheOperationContext { - - private final CacheOperation operation; - - private final Collection caches; - - private final Object target; - - private final Method method; - - private final Object[] args; - - // context passed around to avoid multiple creations - private final EvaluationContext evalContext; - - 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; - - this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass); - } - - protected boolean isConditionPassing() { - if (StringUtils.hasText(this.operation.getCondition())) { - return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext); - } - return true; - } - - /** - * Computes the key for the given caching operation. - * @return generated key (null if none can be generated) - */ - protected Object generateKey() { - if (StringUtils.hasText(this.operation.getKey())) { - return evaluator.key(this.operation.getKey(), this.method, this.evalContext); - } - return keyGenerator.generate(this.target, this.method, this.args); - } - - protected Collection getCaches() { - return this.caches; - } - } -} \ No newline at end of file +/* + * Copyright 2002-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.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.expression.EvaluationContext; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +/** + * Base class for caching aspects, such as the {@link CacheInterceptor} + * or an AspectJ aspect. + * + *

This enables the underlying Spring caching infrastructure to be + * used easily to implement an aspect for any aspect system. + * + *

Subclasses are responsible for calling methods in this class in + * the correct order. + * + *

Uses the Strategy design pattern. A {@link CacheManager} + * implementation will perform the actual cache management, and a + * {@link CacheOperationSource} is used for determining caching + * operation definitions. + * + *

A cache aspect is serializable if its {@code CacheManager} and + * {@code CacheOperationSource} are serializable. + * + * @author Costin Leau + * @author Juergen Hoeller + * @author Chris Beams + * @since 3.1 + */ +public abstract class CacheAspectSupport implements InitializingBean { + + public interface Invoker { + Object invoke(); + } + + protected final Log logger = LogFactory.getLog(getClass()); + + private CacheManager cacheManager; + + private CacheOperationSource cacheOperationSource; + + private final ExpressionEvaluator evaluator = new ExpressionEvaluator(); + + private KeyGenerator keyGenerator = new DefaultKeyGenerator(); + + private boolean initialized = false; + + private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict"; + + /** + * Set the CacheManager that this cache aspect should delegate to. + */ + public void setCacheManager(CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + /** + * Return the CacheManager that this cache aspect delegates to. + */ + public CacheManager getCacheManager() { + return this.cacheManager; + } + + /** + * Set one or more cache definition sources which are used to find the cache + * attributes. If more than one source is provided, they will be aggregated using a + * {@link CompositeCacheOperationSource}. + * @param cacheOperationSources must not be {@code null} + */ + public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) { + Assert.notEmpty(cacheOperationSources); + this.cacheOperationSource = + (cacheOperationSources.length > 1 ? + new CompositeCacheOperationSource(cacheOperationSources) : + cacheOperationSources[0]); + } + + /** + * Return the CacheOperationSource for this cache aspect. + */ + public CacheOperationSource getCacheOperationSource() { + return this.cacheOperationSource; + } + + /** + * Set the KeyGenerator for this cache aspect. + * Default is {@link DefaultKeyGenerator}. + */ + public void setKeyGenerator(KeyGenerator keyGenerator) { + this.keyGenerator = keyGenerator; + } + + /** + * Return the KeyGenerator for this cache aspect, + */ + public KeyGenerator getKeyGenerator() { + return this.keyGenerator; + } + + public void afterPropertiesSet() { + if (this.cacheManager == null) { + throw new IllegalStateException("'cacheManager' is required"); + } + if (this.cacheOperationSource == null) { + throw new IllegalStateException("Either 'cacheDefinitionSource' or 'cacheDefinitionSources' is required: " + + "If there are no cacheable methods, then don't use a cache aspect."); + } + + this.initialized = true; + } + + /** + * Convenience method to return a String representation of this Method + * for use in logging. Can be overridden in subclasses to provide a + * different identifier for the given method. + * @param method the method we're interested in + * @param targetClass class the method is on + * @return log message identifying this method + * @see org.springframework.util.ClassUtils#getQualifiedMethodName + */ + protected String methodIdentification(Method method, Class targetClass) { + Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); + return ClassUtils.getQualifiedMethodName(specificMethod); + } + + protected Collection getCaches(CacheOperation operation) { + Set cacheNames = operation.getCacheNames(); + Collection caches = new ArrayList(cacheNames.size()); + for (String cacheName : cacheNames) { + Cache cache = this.cacheManager.getCache(cacheName); + if (cache == null) { + throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation); + } + caches.add(cache); + } + return caches; + } + + protected CacheOperationContext getOperationContext(CacheOperation operation, Method method, Object[] args, + Object target, Class targetClass) { + + return new CacheOperationContext(operation, method, args, target, targetClass); + } + + protected Object execute(Invoker invoker, Object target, Method method, Object[] args) { + // check whether aspect is enabled + // to cope with cases where the AJ is pulled in automatically + if (!this.initialized) { + return invoker.invoke(); + } + + // get backing class + Class targetClass = AopProxyUtils.ultimateTargetClass(target); + if (targetClass == null && target != null) { + targetClass = target.getClass(); + } + final Collection cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass); + + // analyze caching information + if (!CollectionUtils.isEmpty(cacheOp)) { + Map> ops = createOperationContext(cacheOp, method, args, target, + targetClass); + + // start with evictions + inspectCacheEvicts(ops.get(EVICT)); + + // follow up with cacheable + CacheStatus status = inspectCacheables(ops.get(CACHEABLE)); + + Object retVal = null; + Map updates = inspectCacheUpdates(ops.get(UPDATE)); + + if (status != null) { + if (status.updateRequired) { + updates.putAll(status.cUpdates); + } + // return cached object + else { + return status.retVal; + } + } + + retVal = invoker.invoke(); + + if (!updates.isEmpty()) { + update(updates, retVal); + } + + return retVal; + } + + return invoker.invoke(); + } + + private void inspectCacheEvicts(Collection evictions) { + + if (!evictions.isEmpty()) { + + boolean log = logger.isTraceEnabled(); + + for (CacheOperationContext context : evictions) { + if (context.isConditionPassing()) { + CacheEvictOperation evictOp = (CacheEvictOperation) context.operation; + + // for each cache + // lazy key initialization + Object key = null; + + for (Cache cache : context.getCaches()) { + // cache-wide flush + if (evictOp.isCacheWide()) { + cache.clear(); + if (log) { + logger.trace("Invalidating entire cache for definition " + evictOp + " on method " + context.method); + } + } else { + // check key + if (key == null) { + key = context.generateKey(); + } + if (log) { + logger.trace("Invalidating cache key " + key + " for definition " + evictOp + " on method " + context.method); + } + cache.evict(key); + } + } + } + else { + if (log) { + logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation); + } + } + } + } + } + + private CacheStatus inspectCacheables(Collection cacheables) { + Map cUpdates = new LinkedHashMap( + cacheables.size()); + + boolean updateRequire = false; + Object retVal = null; + + if (!cacheables.isEmpty()) { + boolean log = logger.isTraceEnabled(); + boolean atLeastOnePassed = false; + + for (CacheOperationContext context : cacheables) { + if (context.isConditionPassing()) { + atLeastOnePassed = true; + Object key = context.generateKey(); + + if (log) { + logger.trace("Computed cache key " + key + " for definition " + context.operation); + } + if (key == null) { + throw new IllegalArgumentException( + "Null key returned for cache definition (maybe you are using named params on classes without debug info?) " + + context.operation); + } + + // add op/key (in case an update is discovered later on) + cUpdates.put(context, key); + + boolean localCacheHit = false; + + // check whether the cache needs to be inspected or not (the method will be invoked anyway) + if (!updateRequire) { + for (Cache cache : context.getCaches()) { + Cache.ValueWrapper wrapper = cache.get(key); + if (wrapper != null) { + retVal = wrapper.get(); + localCacheHit = true; + break; + } + } + } + + if (!localCacheHit) { + updateRequire = true; + } + } + else { + if (log) { + logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation); + } + } + } + + // return a status only if at least on cacheable matched + if (atLeastOnePassed) { + return new CacheStatus(cUpdates, updateRequire, retVal); + } + } + + return null; + } + + private static class CacheStatus { + // caches/key + final Map cUpdates; + final boolean updateRequired; + final Object retVal; + + CacheStatus(Map cUpdates, boolean updateRequired, Object retVal) { + this.cUpdates = cUpdates; + this.updateRequired = updateRequired; + this.retVal = retVal; + } + } + + private Map inspectCacheUpdates(Collection updates) { + + Map cUpdates = new LinkedHashMap(updates.size()); + + if (!updates.isEmpty()) { + boolean log = logger.isTraceEnabled(); + + for (CacheOperationContext context : updates) { + if (context.isConditionPassing()) { + + Object key = context.generateKey(); + + if (log) { + logger.trace("Computed cache key " + key + " for definition " + context.operation); + } + if (key == null) { + throw new IllegalArgumentException( + "Null key returned for cache definition (maybe you are using named params on classes without debug info?) " + + context.operation); + } + + // add op/key (in case an update is discovered later on) + cUpdates.put(context, key); + } + else { + if (log) { + logger.trace("Cache condition failed on method " + context.method + " for definition " + context.operation); + } + } + } + } + + return cUpdates; + } + + private void update(Map updates, Object retVal) { + for (Map.Entry entry : updates.entrySet()) { + for (Cache cache : entry.getKey().getCaches()) { + cache.put(entry.getValue(), retVal); + } + } + } + + private Map> createOperationContext(Collection cacheOp, + Method method, Object[] args, Object target, Class targetClass) { + Map> map = new LinkedHashMap>(3); + + Collection cacheables = new ArrayList(); + Collection evicts = new ArrayList(); + Collection updates = new ArrayList(); + + for (CacheOperation cacheOperation : cacheOp) { + CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass); + + if (cacheOperation instanceof CacheableOperation) { + cacheables.add(opContext); + } + + if (cacheOperation instanceof CacheEvictOperation) { + evicts.add(opContext); + } + + if (cacheOperation instanceof CachePutOperation) { + updates.add(opContext); + } + } + + map.put(CACHEABLE, cacheables); + map.put(EVICT, evicts); + map.put(UPDATE, updates); + + return map; + } + + protected class CacheOperationContext { + + private final CacheOperation operation; + + private final Collection caches; + + private final Object target; + + private final Method method; + + private final Object[] args; + + // context passed around to avoid multiple creations + private final EvaluationContext evalContext; + + 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; + + this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass); + } + + protected boolean isConditionPassing() { + if (StringUtils.hasText(this.operation.getCondition())) { + return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext); + } + return true; + } + + /** + * Computes the key for the given caching operation. + * @return generated key (null if none can be generated) + */ + protected Object generateKey() { + if (StringUtils.hasText(this.operation.getKey())) { + return evaluator.key(this.operation.getKey(), this.method, this.evalContext); + } + return keyGenerator.generate(this.target, this.method, this.args); + } + + protected Collection getCaches() { + return this.caches; + } + } +} 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 index c9c47dcd521..d9efe270914 100644 --- 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 @@ -1,44 +1,44 @@ -/* - * Copyright 2002-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 a cache 'evict' operation. - * - * @author Costin Leau - * @since 3.1 - */ -public class CacheEvictOperation extends CacheOperation { - - private boolean cacheWide = false; - - public void setCacheWide(boolean cacheWide) { - this.cacheWide = cacheWide; - } - - public boolean isCacheWide() { - return this.cacheWide; - } - - @Override - protected StringBuilder getOperationDescription() { - StringBuilder sb = super.getOperationDescription(); - sb.append(","); - sb.append(this.cacheWide); - return sb; - } -} +/* + * Copyright 2002-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 a cache 'evict' operation. + * + * @author Costin Leau + * @since 3.1 + */ +public class CacheEvictOperation extends CacheOperation { + + private boolean cacheWide = false; + + public void setCacheWide(boolean cacheWide) { + this.cacheWide = cacheWide; + } + + public boolean isCacheWide() { + return this.cacheWide; + } + + @Override + protected StringBuilder getOperationDescription() { + StringBuilder sb = super.getOperationDescription(); + sb.append(","); + sb.append(this.cacheWide); + return sb; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheExpressionRootObject.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheExpressionRootObject.java index af534a476bf..525cf043d7f 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheExpressionRootObject.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheExpressionRootObject.java @@ -1,81 +1,81 @@ -/* - * Copyright 2002-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.util.Collection; - -import org.springframework.cache.Cache; -import org.springframework.util.Assert; - -/** - * Class describing the root object used during the expression evaluation. - * - * @author Costin Leau - * @since 3.1 - */ -class CacheExpressionRootObject { - - private final Collection caches; - - private final Method method; - - private final Object[] args; - - private final Object target; - - private final Class targetClass; - - - public CacheExpressionRootObject( - Collection caches, Method method, Object[] args, Object target, Class targetClass) { - - Assert.notNull(method, "Method is required"); - Assert.notNull(targetClass, "targetClass is required"); - this.method = method; - this.target = target; - this.targetClass = targetClass; - this.args = args; - this.caches = caches; - } - - - public Collection getCaches() { - return this.caches; - } - - public Method getMethod() { - return this.method; - } - - public String getMethodName() { - return this.method.getName(); - } - - public Object[] getArgs() { - return this.args; - } - - public Object getTarget() { - return this.target; - } - - public Class getTargetClass() { - return this.targetClass; - } - -} +/* + * Copyright 2002-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.util.Collection; + +import org.springframework.cache.Cache; +import org.springframework.util.Assert; + +/** + * Class describing the root object used during the expression evaluation. + * + * @author Costin Leau + * @since 3.1 + */ +class CacheExpressionRootObject { + + private final Collection caches; + + private final Method method; + + private final Object[] args; + + private final Object target; + + private final Class targetClass; + + + public CacheExpressionRootObject( + Collection caches, Method method, Object[] args, Object target, Class targetClass) { + + Assert.notNull(method, "Method is required"); + Assert.notNull(targetClass, "targetClass is required"); + this.method = method; + this.target = target; + this.targetClass = targetClass; + this.args = args; + this.caches = caches; + } + + + public Collection getCaches() { + return this.caches; + } + + public Method getMethod() { + return this.method; + } + + public String getMethodName() { + return this.method.getName(); + } + + public Object[] getArgs() { + return this.args; + } + + public Object getTarget() { + return this.target; + } + + public Class getTargetClass() { + return this.targetClass; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInterceptor.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInterceptor.java index a6f9836c82c..9358a5b07cb 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInterceptor.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheInterceptor.java @@ -1,71 +1,71 @@ -/* - * Copyright 2002-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.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -/** - * AOP Alliance MethodInterceptor for declarative cache - * management using the common Spring caching infrastructure - * ({@link org.springframework.cache.Cache}). - * - *

Derives from the {@link CacheAspectSupport} class which - * contains the integration with Spring's underlying caching API. - * CacheInterceptor simply calls the relevant superclass methods - * in the correct order. - * - *

CacheInterceptors are thread-safe. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -@SuppressWarnings("serial") -public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable { - - private static class ThrowableWrapper extends RuntimeException { - private final Throwable original; - - ThrowableWrapper(Throwable original) { - this.original = original; - } - } - - public Object invoke(final MethodInvocation invocation) throws Throwable { - Method method = invocation.getMethod(); - - Invoker aopAllianceInvoker = new Invoker() { - public Object invoke() { - try { - return invocation.proceed(); - } catch (Throwable ex) { - throw new ThrowableWrapper(ex); - } - } - }; - - try { - return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments()); - } catch (ThrowableWrapper th) { - throw th.original; - } - } -} \ No newline at end of file +/* + * Copyright 2002-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.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * AOP Alliance MethodInterceptor for declarative cache + * management using the common Spring caching infrastructure + * ({@link org.springframework.cache.Cache}). + * + *

Derives from the {@link CacheAspectSupport} class which + * contains the integration with Spring's underlying caching API. + * CacheInterceptor simply calls the relevant superclass methods + * in the correct order. + * + *

CacheInterceptors are thread-safe. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +@SuppressWarnings("serial") +public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable { + + private static class ThrowableWrapper extends RuntimeException { + private final Throwable original; + + ThrowableWrapper(Throwable original) { + this.original = original; + } + } + + public Object invoke(final MethodInvocation invocation) throws Throwable { + Method method = invocation.getMethod(); + + Invoker aopAllianceInvoker = new Invoker() { + public Object invoke() { + try { + return invocation.proceed(); + } catch (Throwable ex) { + throw new ThrowableWrapper(ex); + } + } + }; + + try { + return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments()); + } catch (ThrowableWrapper th) { + throw th.original; + } + } +} 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 index 9a06a457bde..c9a5fce4e0b 100644 --- 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 @@ -1,128 +1,128 @@ -/* - * Copyright 2002-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(this.name); - result.append("] caches="); - result.append(this.cacheNames); - result.append(" | condition='"); - result.append(this.condition); - result.append("' | key='"); - result.append(this.key); - result.append("'"); - return result; - } -} \ No newline at end of file +/* + * Copyright 2002-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 {@code toString()} results. + * @see #toString() + */ + @Override + public boolean equals(Object other) { + return (other instanceof CacheOperation && toString().equals(other.toString())); + } + + /** + * This implementation returns {@code 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 {@code equals} + * and {@code 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 {@code toString()} result. + */ + protected StringBuilder getOperationDescription() { + StringBuilder result = new StringBuilder(); + result.append("CacheDefinition["); + result.append(this.name); + result.append("] caches="); + result.append(this.cacheNames); + result.append(" | condition='"); + result.append(this.condition); + result.append("' | key='"); + result.append(this.key); + result.append("'"); + return result; + } +} 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 index 7d45ec504df..fb75394d6ca 100644 --- 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 @@ -1,43 +1,43 @@ -/* - * Copyright 2002-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.util.Collection; - -/** - * 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 - * @since 3.1 - */ -public interface CacheOperationSource { - - /** - * Return the cache operation definition for this method, - * or null if the method contains no "cacheable" annotations. - * @param method the method to introspect - * @param targetClass the 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 - */ - Collection getCacheOperations(Method method, Class targetClass); - -} +/* + * Copyright 2002-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.util.Collection; + +/** + * 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 + * @since 3.1 + */ +public interface CacheOperationSource { + + /** + * Return the cache operation definition for this method, + * or {@code null} if the method contains no "cacheable" annotations. + * @param method the method to introspect + * @param targetClass the target class (may be {@code null}, + * in which case the declaring class of the method must be used) + * @return {@link CacheOperation} the matching cache operation, + * or {@code null} if none found + */ + Collection getCacheOperations(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 index 9f357431100..7fd2bb3d43c 100644 --- 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 @@ -1,71 +1,71 @@ -/* - * Copyright 2002-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.CollectionUtils; -import org.springframework.util.ObjectUtils; - -/** - * A Pointcut that matches if the underlying {@link CacheOperationSource} - * has an attribute for a given method. - * - * @author Costin Leau - * @since 3.1 - */ -@SuppressWarnings("serial") -abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { - - public boolean matches(Method method, Class targetClass) { - CacheOperationSource cas = getCacheOperationSource(); - return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass))); - } - - @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(); - -} +/* + * Copyright 2002-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.CollectionUtils; +import org.springframework.util.ObjectUtils; + +/** + * A Pointcut that matches if the underlying {@link CacheOperationSource} + * has an attribute for a given method. + * + * @author Costin Leau + * @since 3.1 + */ +@SuppressWarnings("serial") +abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { + + public boolean matches(Method method, Class targetClass) { + CacheOperationSource cas = getCacheOperationSource(); + return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass))); + } + + @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 {@code null}). + * To be implemented by subclasses. + */ + protected abstract CacheOperationSource getCacheOperationSource(); + +} 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 5504fe57566..2db32e27a35 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 @@ -1,79 +1,79 @@ -/* - * 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.Pointcut; -import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean; -import org.springframework.aop.support.DefaultPointcutAdvisor; - -/** - * Proxy factory bean for simplified declarative caching handling. - * This is a convenient alternative to a standard AOP - * {@link org.springframework.aop.framework.ProxyFactoryBean} - * with a separate {@link CachingInterceptor} definition. - * - *

This class is designed to facilitate declarative cache demarcation: namely, wrapping - * a singleton target object with a caching proxy, proxying all the interfaces that the - * target implements. Exists primarily for third-party framework integration. - * Users should favor the {@code cache:} XML namespace - * {@link org.springframework.cache.annotation.Cacheable @Cacheable} annotation. - * See the declarative annotation-based caching section - * of the Spring reference documentation for more information. - * - * @author Costin Leau - * @see org.springframework.aop.framework.ProxyFactoryBean - * @see CachingInterceptor - */ -@SuppressWarnings("serial") -public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean { - - private final CacheInterceptor cachingInterceptor = new CacheInterceptor(); - private Pointcut pointcut; - - /** - * Set a pointcut, i.e a bean that can cause conditional invocation - * of the CacheInterceptor depending on method and attributes passed. - * Note: Additional interceptors are always invoked. - * @see #setPreInterceptors - * @see #setPostInterceptors - */ - public void setPointcut(Pointcut pointcut) { - this.pointcut = pointcut; - } - - @Override - protected Object createMainInterceptor() { - this.cachingInterceptor.afterPropertiesSet(); - if (this.pointcut != null) { - return new DefaultPointcutAdvisor(this.pointcut, this.cachingInterceptor); - } else { - // Rely on default pointcut. - throw new UnsupportedOperationException(); - } - } - - /** - * Set the caching attribute source which is used to find the cache operation - * definition. - * - * @param cacheDefinitionSources cache definition sources - */ - public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) { - this.cachingInterceptor.setCacheOperationSources(cacheDefinitionSources); - } - -} +/* + * 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.Pointcut; +import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean; +import org.springframework.aop.support.DefaultPointcutAdvisor; + +/** + * Proxy factory bean for simplified declarative caching handling. + * This is a convenient alternative to a standard AOP + * {@link org.springframework.aop.framework.ProxyFactoryBean} + * with a separate {@link CachingInterceptor} definition. + * + *

This class is designed to facilitate declarative cache demarcation: namely, wrapping + * a singleton target object with a caching proxy, proxying all the interfaces that the + * target implements. Exists primarily for third-party framework integration. + * Users should favor the {@code cache:} XML namespace + * {@link org.springframework.cache.annotation.Cacheable @Cacheable} annotation. + * See the declarative annotation-based caching section + * of the Spring reference documentation for more information. + * + * @author Costin Leau + * @see org.springframework.aop.framework.ProxyFactoryBean + * @see CachingInterceptor + */ +@SuppressWarnings("serial") +public class CacheProxyFactoryBean extends AbstractSingletonProxyFactoryBean { + + private final CacheInterceptor cachingInterceptor = new CacheInterceptor(); + private Pointcut pointcut; + + /** + * Set a pointcut, i.e a bean that can cause conditional invocation + * of the CacheInterceptor depending on method and attributes passed. + * Note: Additional interceptors are always invoked. + * @see #setPreInterceptors + * @see #setPostInterceptors + */ + public void setPointcut(Pointcut pointcut) { + this.pointcut = pointcut; + } + + @Override + protected Object createMainInterceptor() { + this.cachingInterceptor.afterPropertiesSet(); + if (this.pointcut != null) { + return new DefaultPointcutAdvisor(this.pointcut, this.cachingInterceptor); + } else { + // Rely on default pointcut. + throw new UnsupportedOperationException(); + } + } + + /** + * Set the caching attribute source which is used to find the cache operation + * definition. + * + * @param cacheDefinitionSources cache definition sources + */ + public void setCacheDefinitionSources(CacheOperationSource... cacheDefinitionSources) { + this.cachingInterceptor.setCacheOperationSources(cacheDefinitionSources); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java index 5a54b72b680..edb84ba156b 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java @@ -1,27 +1,27 @@ -/* - * 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; - -/** - * Class describing a cache 'put' operation. - * - * @author Costin Leau - * @since 3.1 - */ -public class CachePutOperation extends CacheOperation { - -} +/* + * Copyright 2002-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 a cache 'put' operation. + * + * @author Costin Leau + * @since 3.1 + */ +public class CachePutOperation extends CacheOperation { + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java index a00eeff3044..23c0b20e2c8 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java @@ -1,27 +1,27 @@ -/* - * Copyright 2002-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 a cache 'cacheable' operation. - * - * @author Costin Leau - * @since 3.1 - */ -public class CacheableOperation extends CacheOperation { - -} +/* + * Copyright 2002-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 a cache 'cacheable' operation. + * + * @author Costin Leau + * @since 3.1 + */ +public class CacheableOperation 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 index 2ee5d23f4b9..3e96751a51f 100644 --- 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 @@ -1,69 +1,69 @@ -/* - * Copyright 2002-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 java.util.ArrayList; -import java.util.Collection; - -import org.springframework.util.Assert; - -/** - * Composite {@link CacheOperationSource} implementation that iterates - * over a given array of {@link CacheOperationSource} instances. - * - * @author Costin Leau - * @since 3.1 - */ -@SuppressWarnings("serial") -public class CompositeCacheOperationSource implements CacheOperationSource, Serializable { - - private final CacheOperationSource[] cacheOperationSources; - - /** - * Create a new CompositeCacheOperationSource for the given sources. - * @param cacheOperationSources the CacheOperationSource instances to combine - */ - public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) { - Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty"); - this.cacheOperationSources = cacheOperationSources; - } - - /** - * Return the CacheOperationSource instances that this CompositeCachingDefinitionSource combines. - */ - public final CacheOperationSource[] getCacheOperationSources() { - return this.cacheOperationSources; - } - - public Collection getCacheOperations(Method method, Class targetClass) { - Collection ops = null; - - for (CacheOperationSource source : this.cacheOperationSources) { - Collection cacheOperations = source.getCacheOperations(method, targetClass); - if (cacheOperations != null) { - if (ops == null) { - ops = new ArrayList(); - } - - ops.addAll(cacheOperations); - } - } - return ops; - } -} +/* + * Copyright 2002-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 java.util.ArrayList; +import java.util.Collection; + +import org.springframework.util.Assert; + +/** + * Composite {@link CacheOperationSource} implementation that iterates + * over a given array of {@link CacheOperationSource} instances. + * + * @author Costin Leau + * @since 3.1 + */ +@SuppressWarnings("serial") +public class CompositeCacheOperationSource implements CacheOperationSource, Serializable { + + private final CacheOperationSource[] cacheOperationSources; + + /** + * Create a new CompositeCacheOperationSource for the given sources. + * @param cacheOperationSources the CacheOperationSource instances to combine + */ + public CompositeCacheOperationSource(CacheOperationSource... cacheOperationSources) { + Assert.notEmpty(cacheOperationSources, "cacheOperationSources array must not be empty"); + this.cacheOperationSources = cacheOperationSources; + } + + /** + * Return the CacheOperationSource instances that this CompositeCachingDefinitionSource combines. + */ + public final CacheOperationSource[] getCacheOperationSources() { + return this.cacheOperationSources; + } + + public Collection getCacheOperations(Method method, Class targetClass) { + Collection ops = null; + + for (CacheOperationSource source : this.cacheOperationSources) { + Collection cacheOperations = source.getCacheOperations(method, targetClass); + if (cacheOperations != null) { + if (ops == null) { + ops = new ArrayList(); + } + + ops.addAll(cacheOperations); + } + } + return ops; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultKeyGenerator.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultKeyGenerator.java index 55cd2a54a27..cb0dcc95d8c 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultKeyGenerator.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/DefaultKeyGenerator.java @@ -1,52 +1,53 @@ -/* - * Copyright 2002-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 org.springframework.cache.interceptor.KeyGenerator; - -/** - * Default key generator. Returns {@value #NO_PARAM_KEY} if no parameters are provided, - * the parameter itself if only one is given or a hash code computed from all given - * parameters' hash code values. Uses the constant value {@value #NULL_PARAM_KEY} for any - * {@code null} parameters given. - * - * @author Costin Leau - * @author Chris Beams - * @since 3.1 - */ -public class DefaultKeyGenerator implements KeyGenerator { - - public static final int NO_PARAM_KEY = 0; - public static final int NULL_PARAM_KEY = 53; - - public Object generate(Object target, Method method, Object... params) { - if (params.length == 1) { - return (params[0] == null ? NULL_PARAM_KEY : params[0]); - } - if (params.length == 0) { - return NO_PARAM_KEY; - } - int hashCode = 17; - for (Object object : params) { - hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode()); - } - return Integer.valueOf(hashCode); - } - -} +/* + * Copyright 2002-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 org.springframework.cache.interceptor.KeyGenerator; + +/** + * Default key generator. Returns {@value #NO_PARAM_KEY} if no + * parameters are provided, the parameter itself if only one is given or + * a hash code computed from all given parameters' hash code values. + * Uses the constant value {@value #NULL_PARAM_KEY} for any + * {@code null} parameters given. + * + * @author Costin Leau + * @author Chris Beams + * @since 3.1 + */ +public class DefaultKeyGenerator implements KeyGenerator { + + public static final int NO_PARAM_KEY = 0; + public static final int NULL_PARAM_KEY = 53; + + public Object generate(Object target, Method method, Object... params) { + if (params.length == 1) { + return (params[0] == null ? NULL_PARAM_KEY : params[0]); + } + if (params.length == 0) { + return NO_PARAM_KEY; + } + int hashCode = 17; + for (Object object : params) { + hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode()); + } + return Integer.valueOf(hashCode); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/ExpressionEvaluator.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/ExpressionEvaluator.java index 2049ad03863..4db94bb1b07 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/ExpressionEvaluator.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/ExpressionEvaluator.java @@ -1,81 +1,81 @@ -/* - * Copyright 2002-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.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.cache.Cache; -import org.springframework.core.LocalVariableTableParameterNameDiscoverer; -import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; - -/** - * Utility class handling the SpEL expression parsing. - * Meant to be used as a reusable, thread-safe component. - * - *

Performs internal caching for performance reasons. - * - * @author Costin Leau - * @since 3.1 - */ -class ExpressionEvaluator { - - private SpelExpressionParser parser = new SpelExpressionParser(); - - // shared param discoverer since it caches data internally - private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); - - private Map conditionCache = new ConcurrentHashMap(); - - private Map keyCache = new ConcurrentHashMap(); - - private Map targetMethodCache = new ConcurrentHashMap(); - - - public EvaluationContext createEvaluationContext( - Collection caches, Method method, Object[] args, Object target, Class targetClass) { - - CacheExpressionRootObject rootObject = - new CacheExpressionRootObject(caches, method, args, target, targetClass); - return new LazyParamAwareEvaluationContext(rootObject, - this.paramNameDiscoverer, method, args, targetClass, this.targetMethodCache); - } - - public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) { - Expression condExp = this.conditionCache.get(method); - if (condExp == null) { - condExp = this.parser.parseExpression(conditionExpression); - this.conditionCache.put(method, condExp); - } - return condExp.getValue(evalContext, boolean.class); - } - - public Object key(String keyExpression, Method method, EvaluationContext evalContext) { - Expression keyExp = this.keyCache.get(method); - if (keyExp == null) { - keyExp = this.parser.parseExpression(keyExpression); - this.keyCache.put(method, keyExp); - } - return keyExp.getValue(evalContext); - } - -} +/* + * Copyright 2002-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.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.cache.Cache; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +/** + * Utility class handling the SpEL expression parsing. + * Meant to be used as a reusable, thread-safe component. + * + *

Performs internal caching for performance reasons. + * + * @author Costin Leau + * @since 3.1 + */ +class ExpressionEvaluator { + + private SpelExpressionParser parser = new SpelExpressionParser(); + + // shared param discoverer since it caches data internally + private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); + + private Map conditionCache = new ConcurrentHashMap(); + + private Map keyCache = new ConcurrentHashMap(); + + private Map targetMethodCache = new ConcurrentHashMap(); + + + public EvaluationContext createEvaluationContext( + Collection caches, Method method, Object[] args, Object target, Class targetClass) { + + CacheExpressionRootObject rootObject = + new CacheExpressionRootObject(caches, method, args, target, targetClass); + return new LazyParamAwareEvaluationContext(rootObject, + this.paramNameDiscoverer, method, args, targetClass, this.targetMethodCache); + } + + public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) { + Expression condExp = this.conditionCache.get(method); + if (condExp == null) { + condExp = this.parser.parseExpression(conditionExpression); + this.conditionCache.put(method, condExp); + } + return condExp.getValue(evalContext, boolean.class); + } + + public Object key(String keyExpression, Method method, EvaluationContext evalContext) { + Expression keyExp = this.keyCache.get(method); + if (keyExp == null) { + keyExp = this.parser.parseExpression(keyExpression); + this.keyCache.put(method, keyExp); + } + return keyExp.getValue(evalContext); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/KeyGenerator.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/KeyGenerator.java index b9009b8cefe..e7cd01a5b01 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/KeyGenerator.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/KeyGenerator.java @@ -1,33 +1,33 @@ -/* - * Copyright 2002-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; - -/** - * Cache key generator. Used for creating a key based on the given method - * (used as context) and its parameters. - * - * @author Costin Leau - * @author Chris Beams - * @since 3.1 - */ -public interface KeyGenerator { - - Object generate(Object target, Method method, Object... params); - -} +/* + * Copyright 2002-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; + +/** + * Cache key generator. Used for creating a key based on the given method + * (used as context) and its parameters. + * + * @author Costin Leau + * @author Chris Beams + * @since 3.1 + */ +public interface KeyGenerator { + + Object generate(Object target, Method method, Object... params); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/LazyParamAwareEvaluationContext.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/LazyParamAwareEvaluationContext.java index 9cb14ff7e4b..f8a5b00f9cc 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/LazyParamAwareEvaluationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/LazyParamAwareEvaluationContext.java @@ -1,111 +1,111 @@ -/* - * Copyright 2002-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.util.Map; - -import org.springframework.aop.support.AopUtils; -import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.util.ObjectUtils; - -/** - * Evaluation context class that adds a method parameters as SpEL variables, - * in a lazy manner. The lazy nature eliminates unneeded parsing of classes - * byte code for parameter discovery. - * - *

To limit the creation of objects, an ugly constructor is used (rather then - * a dedicated 'closure'-like class for deferred execution). - * - * @author Costin Leau - * @since 3.1 - */ -class LazyParamAwareEvaluationContext extends StandardEvaluationContext { - - private final ParameterNameDiscoverer paramDiscoverer; - - private final Method method; - - private final Object[] args; - - private final Class targetClass; - - private final Map methodCache; - - private boolean paramLoaded = false; - - - LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method, - Object[] args, Class targetClass, Map methodCache) { - super(rootObject); - - this.paramDiscoverer = paramDiscoverer; - this.method = method; - this.args = args; - this.targetClass = targetClass; - this.methodCache = methodCache; - } - - - /** - * Load the param information only when needed. - */ - @Override - public Object lookupVariable(String name) { - Object variable = super.lookupVariable(name); - if (variable != null) { - return variable; - } - if (!this.paramLoaded) { - loadArgsAsVariables(); - this.paramLoaded = true; - variable = super.lookupVariable(name); - } - return variable; - } - - private void loadArgsAsVariables() { - // shortcut if no args need to be loaded - if (ObjectUtils.isEmpty(this.args)) { - return; - } - - Method targetMethod = this.methodCache.get(this.method); - if (targetMethod == null) { - targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass); - if (targetMethod == null) { - targetMethod = this.method; - } - this.methodCache.put(this.method, targetMethod); - } - - // save arguments as indexed variables - for (int i = 0; i < this.args.length; i++) { - setVariable("p" + i, this.args[i]); - } - - String[] parameterNames = this.paramDiscoverer.getParameterNames(targetMethod); - // save parameter names (if discovered) - if (parameterNames != null) { - for (int i = 0; i < parameterNames.length; i++) { - setVariable(parameterNames[i], this.args[i]); - } - } - } - -} +/* + * Copyright 2002-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.util.Map; + +import org.springframework.aop.support.AopUtils; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.ObjectUtils; + +/** + * Evaluation context class that adds a method parameters as SpEL + * variables, in a lazy manner. The lazy nature eliminates unneeded + * parsing of classes byte code for parameter discovery. + * + *

To limit the creation of objects, an ugly constructor is used + * (rather then a dedicated 'closure'-like class for deferred execution). + * + * @author Costin Leau + * @since 3.1 + */ +class LazyParamAwareEvaluationContext extends StandardEvaluationContext { + + private final ParameterNameDiscoverer paramDiscoverer; + + private final Method method; + + private final Object[] args; + + private final Class targetClass; + + private final Map methodCache; + + private boolean paramLoaded = false; + + + LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method, + Object[] args, Class targetClass, Map methodCache) { + super(rootObject); + + this.paramDiscoverer = paramDiscoverer; + this.method = method; + this.args = args; + this.targetClass = targetClass; + this.methodCache = methodCache; + } + + + /** + * Load the param information only when needed. + */ + @Override + public Object lookupVariable(String name) { + Object variable = super.lookupVariable(name); + if (variable != null) { + return variable; + } + if (!this.paramLoaded) { + loadArgsAsVariables(); + this.paramLoaded = true; + variable = super.lookupVariable(name); + } + return variable; + } + + private void loadArgsAsVariables() { + // shortcut if no args need to be loaded + if (ObjectUtils.isEmpty(this.args)) { + return; + } + + Method targetMethod = this.methodCache.get(this.method); + if (targetMethod == null) { + targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass); + if (targetMethod == null) { + targetMethod = this.method; + } + this.methodCache.put(this.method, targetMethod); + } + + // save arguments as indexed variables + for (int i = 0; i < this.args.length; i++) { + setVariable("p" + i, this.args[i]); + } + + String[] parameterNames = this.paramDiscoverer.getParameterNames(targetMethod); + // save parameter names (if discovered) + if (parameterNames != null) { + for (int i = 0; i < parameterNames.length; i++) { + setVariable(parameterNames[i], this.args[i]); + } + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java index f56c04fa4a0..516ad754ca7 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java @@ -1,128 +1,128 @@ -/* - * 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 java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.util.ObjectUtils; -import org.springframework.util.PatternMatchUtils; - -/** - * Simple {@link CacheOperationSource} implementation that - * allows attributes to be matched by registered name. - * - * @author Costin Leau - */ -public class NameMatchCacheOperationSource implements CacheOperationSource, Serializable { - - /** - * Logger available to subclasses. - *

Static for optimal serialization. - */ - protected static final Log logger = LogFactory.getLog(NameMatchCacheOperationSource.class); - - /** Keys are method names; values are TransactionAttributes */ - private Map> nameMap = new LinkedHashMap>(); - - /** - * Set a name/attribute map, consisting of method names - * (e.g. "myMethod") and CacheOperation instances - * (or Strings to be converted to CacheOperation instances). - * @see CacheOperation - * @see CacheOperationEditor - */ - public void setNameMap(Map> nameMap) { - for (Map.Entry> entry : nameMap.entrySet()) { - addCacheMethod(entry.getKey(), entry.getValue()); - } - } - - /** - * Add an attribute for a cacheable method. - *

Method names can be exact matches, or of the pattern "xxx*", - * "*xxx" or "*xxx*" for matching multiple methods. - * @param methodName the name of the method - * @param ops operation associated with the method - */ - public void addCacheMethod(String methodName, Collection ops) { - if (logger.isDebugEnabled()) { - logger.debug("Adding method [" + methodName + "] with cache operations [" + ops + "]"); - } - this.nameMap.put(methodName, ops); - } - - public Collection getCacheOperations(Method method, Class targetClass) { - // look for direct name match - String methodName = method.getName(); - Collection ops = this.nameMap.get(methodName); - - if (ops == null) { - // Look for most specific name match. - String bestNameMatch = null; - for (String mappedName : this.nameMap.keySet()) { - if (isMatch(methodName, mappedName) - && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) { - ops = this.nameMap.get(mappedName); - bestNameMatch = mappedName; - } - } - } - - return ops; - } - - /** - * Return if the given method name matches the mapped name. - *

The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, - * as well as direct equality. Can be overridden in subclasses. - * @param methodName the method name of the class - * @param mappedName the name in the descriptor - * @return if the names match - * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String) - */ - protected boolean isMatch(String methodName, String mappedName) { - return PatternMatchUtils.simpleMatch(mappedName, methodName); - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof NameMatchCacheOperationSource)) { - return false; - } - NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other; - return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap); - } - - @Override - public int hashCode() { - return NameMatchCacheOperationSource.class.hashCode(); - } - - @Override - public String toString() { - return getClass().getName() + ": " + this.nameMap; - } -} \ No newline at end of file +/* + * 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 java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.ObjectUtils; +import org.springframework.util.PatternMatchUtils; + +/** + * Simple {@link CacheOperationSource} implementation that + * allows attributes to be matched by registered name. + * + * @author Costin Leau + */ +public class NameMatchCacheOperationSource implements CacheOperationSource, Serializable { + + /** + * Logger available to subclasses. + *

Static for optimal serialization. + */ + protected static final Log logger = LogFactory.getLog(NameMatchCacheOperationSource.class); + + /** Keys are method names; values are TransactionAttributes */ + private Map> nameMap = new LinkedHashMap>(); + + /** + * Set a name/attribute map, consisting of method names + * (e.g. "myMethod") and CacheOperation instances + * (or Strings to be converted to CacheOperation instances). + * @see CacheOperation + * @see CacheOperationEditor + */ + public void setNameMap(Map> nameMap) { + for (Map.Entry> entry : nameMap.entrySet()) { + addCacheMethod(entry.getKey(), entry.getValue()); + } + } + + /** + * Add an attribute for a cacheable method. + *

Method names can be exact matches, or of the pattern "xxx*", + * "*xxx" or "*xxx*" for matching multiple methods. + * @param methodName the name of the method + * @param ops operation associated with the method + */ + public void addCacheMethod(String methodName, Collection ops) { + if (logger.isDebugEnabled()) { + logger.debug("Adding method [" + methodName + "] with cache operations [" + ops + "]"); + } + this.nameMap.put(methodName, ops); + } + + public Collection getCacheOperations(Method method, Class targetClass) { + // look for direct name match + String methodName = method.getName(); + Collection ops = this.nameMap.get(methodName); + + if (ops == null) { + // Look for most specific name match. + String bestNameMatch = null; + for (String mappedName : this.nameMap.keySet()) { + if (isMatch(methodName, mappedName) + && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) { + ops = this.nameMap.get(mappedName); + bestNameMatch = mappedName; + } + } + } + + return ops; + } + + /** + * Return if the given method name matches the mapped name. + *

The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches, + * as well as direct equality. Can be overridden in subclasses. + * @param methodName the method name of the class + * @param mappedName the name in the descriptor + * @return if the names match + * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String) + */ + protected boolean isMatch(String methodName, String mappedName) { + return PatternMatchUtils.simpleMatch(mappedName, methodName); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof NameMatchCacheOperationSource)) { + return false; + } + NameMatchCacheOperationSource otherTas = (NameMatchCacheOperationSource) other; + return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap); + } + + @Override + public int hashCode() { + return NameMatchCacheOperationSource.class.hashCode(); + } + + @Override + public String toString() { + return getClass().getName() + ": " + this.nameMap; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/package-info.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/package-info.java index 1b229991d34..943130ebfed 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/package-info.java @@ -1,8 +1,6 @@ -/** - * AOP-based solution for declarative caching demarcation. - * Builds on the AOP infrastructure in org.springframework.aop.framework. - * Any POJO can be cache advised with Spring. - * - */ -package org.springframework.cache.interceptor; - +/** + * AOP-based solution for declarative caching demarcation. + * Builds on the AOP infrastructure in org.springframework.aop.framework. + * Any POJO can be cache-advised with Spring. + */ +package org.springframework.cache.interceptor; diff --git a/org.springframework.context/src/main/java/org/springframework/cache/package-info.java b/org.springframework.context/src/main/java/org/springframework/cache/package-info.java index 79767826c0f..982312e8246 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/package-info.java @@ -1,7 +1,5 @@ -/** - * Spring's generic cache abstraction. - * Concrete implementations are provided in the subpackages. - * - */ -package org.springframework.cache; - +/** + * Spring's generic cache abstraction. + * Concrete implementations are provided in the subpackages. + */ +package org.springframework.cache; diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java index 95dfa7cc7a6..5b25f76420d 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java @@ -1,78 +1,79 @@ -/* - * Copyright 2002-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.support; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; -import org.springframework.util.Assert; - -/** - * Abstract base class implementing the common CacheManager methods. - * Useful for 'static' environments where the backing caches do not change. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -public abstract class AbstractCacheManager implements CacheManager, InitializingBean { - - private final ConcurrentMap cacheMap = new ConcurrentHashMap(); - - private Set cacheNames = new LinkedHashSet(); - - - public void afterPropertiesSet() { - Collection caches = loadCaches(); - Assert.notEmpty(caches, "loadCaches must not return an empty Collection"); - this.cacheMap.clear(); - - // preserve the initial order of the cache names - for (Cache cache : caches) { - this.cacheMap.put(cache.getName(), cache); - this.cacheNames.add(cache.getName()); - } - } - - protected final void addCache(Cache cache) { - this.cacheMap.put(cache.getName(), cache); - this.cacheNames.add(cache.getName()); - } - - public Cache getCache(String name) { - return this.cacheMap.get(name); - } - - public Collection getCacheNames() { - return Collections.unmodifiableSet(this.cacheNames); - } - - - /** - * Load the caches for this cache manager. Occurs at startup. - * The returned collection must not be null. - */ - protected abstract Collection loadCaches(); - -} +/* + * Copyright 2002-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.support; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.util.Assert; + +/** + * Abstract base class implementing the common {@link CacheManager} + * methods. Useful for 'static' environments where the backing caches do + * not change. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +public abstract class AbstractCacheManager implements CacheManager, InitializingBean { + + private final ConcurrentMap cacheMap = new ConcurrentHashMap(); + + private Set cacheNames = new LinkedHashSet(); + + + public void afterPropertiesSet() { + Collection caches = loadCaches(); + Assert.notEmpty(caches, "loadCaches must not return an empty Collection"); + this.cacheMap.clear(); + + // preserve the initial order of the cache names + for (Cache cache : caches) { + this.cacheMap.put(cache.getName(), cache); + this.cacheNames.add(cache.getName()); + } + } + + protected final void addCache(Cache cache) { + this.cacheMap.put(cache.getName(), cache); + this.cacheNames.add(cache.getName()); + } + + public Cache getCache(String name) { + return this.cacheMap.get(name); + } + + public Collection getCacheNames() { + return Collections.unmodifiableSet(this.cacheNames); + } + + + /** + * Load the caches for this cache manager. Occurs at startup. + * The returned collection must not be null. + */ + protected abstract Collection loadCaches(); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java index 494e2fce21f..ab5b96d8674 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java @@ -1,87 +1,87 @@ -/* - * Copyright 2002-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.support; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; -import org.springframework.util.Assert; - -/** - * Composite {@link CacheManager} implementation that iterates - * over a given collection of {@link CacheManager} instances. - * - * Allows {@link NoOpCacheManager} to be automatically added to the list for handling - * the cache declarations without a backing store. - * - * @author Costin Leau - * @author Juergen Hoeller - * @since 3.1 - */ -public class CompositeCacheManager implements InitializingBean, CacheManager { - - private List cacheManagers; - - private boolean fallbackToNoOpCache = false; - - - public void setCacheManagers(Collection cacheManagers) { - Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty"); - this.cacheManagers = new ArrayList(); - this.cacheManagers.addAll(cacheManagers); - } - - /** - * Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists. - * In this case, any getCache requests not handled by the configured cache managers will - * be automatically handled by the {@link NoOpCacheManager} (and hence never return null). - */ - public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) { - this.fallbackToNoOpCache = fallbackToNoOpCache; - } - - public void afterPropertiesSet() { - if (this.fallbackToNoOpCache) { - this.cacheManagers.add(new NoOpCacheManager()); - } - } - - - public Cache getCache(String name) { - for (CacheManager cacheManager : this.cacheManagers) { - Cache cache = cacheManager.getCache(name); - if (cache != null) { - return cache; - } - } - return null; - } - - public Collection getCacheNames() { - List names = new ArrayList(); - for (CacheManager manager : this.cacheManagers) { - names.addAll(manager.getCacheNames()); - } - return Collections.unmodifiableList(names); - } - -} +/* + * Copyright 2002-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.support; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.util.Assert; + +/** + * Composite {@link CacheManager} implementation that iterates + * over a given collection of {@link CacheManager} instances. + * + * Allows {@link NoOpCacheManager} to be automatically added to the list for handling + * the cache declarations without a backing store. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.1 + */ +public class CompositeCacheManager implements InitializingBean, CacheManager { + + private List cacheManagers; + + private boolean fallbackToNoOpCache = false; + + + public void setCacheManagers(Collection cacheManagers) { + Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty"); + this.cacheManagers = new ArrayList(); + this.cacheManagers.addAll(cacheManagers); + } + + /** + * Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists. + * In this case, any {@code getCache} requests not handled by the configured cache managers will + * be automatically handled by the {@link NoOpCacheManager} (and hence never return {@code null}). + */ + public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) { + this.fallbackToNoOpCache = fallbackToNoOpCache; + } + + public void afterPropertiesSet() { + if (this.fallbackToNoOpCache) { + this.cacheManagers.add(new NoOpCacheManager()); + } + } + + + public Cache getCache(String name) { + for (CacheManager cacheManager : this.cacheManagers) { + Cache cache = cacheManager.getCache(name); + if (cache != null) { + return cache; + } + } + return null; + } + + public Collection getCacheNames() { + List names = new ArrayList(); + for (CacheManager manager : this.cacheManagers) { + names.addAll(manager.getCacheNames()); + } + return Collections.unmodifiableList(names); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java index f59f8fd6b42..32ffb8192fa 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java @@ -1,100 +1,101 @@ -/* - * 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.support; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; - -/** - * A basic, no operation {@link CacheManager} implementation suitable for disabling caching, - * typically used for backing cache declarations without an actual backing store. - * - *

Will simply accept any items into the cache not actually storing them. - * - * @author Costin Leau - * @since 3.1 - * @see CompositeCacheManager - */ -public class NoOpCacheManager implements CacheManager { - - private final ConcurrentMap caches = new ConcurrentHashMap(); - private Set names = new LinkedHashSet(); - - private static class NoOpCache implements Cache { - - private final String name; - - public NoOpCache(String name) { - this.name = name; - } - - public void clear() { - } - - public void evict(Object key) { - } - - public ValueWrapper get(Object key) { - return null; - } - - public String getName() { - return name; - } - - public Object getNativeCache() { - return null; - } - - public void put(Object key, Object value) { - } - } - - /** - * {@inheritDoc} - * - * This implementation always returns a {@link Cache} implementation that will not - * store items. Additionally, the request cache will be remembered by the manager for consistency. - */ - public Cache getCache(String name) { - Cache cache = caches.get(name); - if (cache == null) { - caches.putIfAbsent(name, new NoOpCache(name)); - synchronized (names) { - names.add(name); - } - } - - return caches.get(name); - } - - /** - * {@inheritDoc} - * - * This implementation returns the name of the caches previously requested. - */ - public Collection getCacheNames() { - return Collections.unmodifiableSet(names); - } -} \ No newline at end of file +/* + * 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.support; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +/** + * A basic, no operation {@link CacheManager} implementation suitable + * for disabling caching, typically used for backing cache declarations + * without an actual backing store. + * + *

Will simply accept any items into the cache not actually storing them. + * + * @author Costin Leau + * @since 3.1 + * @see CompositeCacheManager + */ +public class NoOpCacheManager implements CacheManager { + + private final ConcurrentMap caches = new ConcurrentHashMap(); + private Set names = new LinkedHashSet(); + + private static class NoOpCache implements Cache { + + private final String name; + + public NoOpCache(String name) { + this.name = name; + } + + public void clear() { + } + + public void evict(Object key) { + } + + public ValueWrapper get(Object key) { + return null; + } + + public String getName() { + return name; + } + + public Object getNativeCache() { + return null; + } + + public void put(Object key, Object value) { + } + } + + /** + * {@inheritDoc} + * + * This implementation always returns a {@link Cache} implementation that will not + * store items. Additionally, the request cache will be remembered by the manager for consistency. + */ + public Cache getCache(String name) { + Cache cache = caches.get(name); + if (cache == null) { + caches.putIfAbsent(name, new NoOpCache(name)); + synchronized (names) { + names.add(name); + } + } + + return caches.get(name); + } + + /** + * {@inheritDoc} + * + * This implementation returns the name of the caches previously requested. + */ + public Collection getCacheNames() { + return Collections.unmodifiableSet(names); + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/SimpleCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/support/SimpleCacheManager.java index 007ba989cde..e90bfaca6b3 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/SimpleCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/SimpleCacheManager.java @@ -1,46 +1,46 @@ -/* - * Copyright 2002-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.support; - -import java.util.Collection; - -import org.springframework.cache.Cache; - -/** - * Simple cache manager working against a given collection of caches. - * Useful for testing or simple caching declarations. - * - * @author Costin Leau - * @since 3.1 - */ -public class SimpleCacheManager extends AbstractCacheManager { - - private Collection caches; - - /** - * Specify the collection of Cache instances to use for this CacheManager. - */ - public void setCaches(Collection caches) { - this.caches = caches; - } - - @Override - protected Collection loadCaches() { - return this.caches; - } - -} +/* + * Copyright 2002-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.support; + +import java.util.Collection; + +import org.springframework.cache.Cache; + +/** + * Simple cache manager working against a given collection of caches. + * Useful for testing or simple caching declarations. + * + * @author Costin Leau + * @since 3.1 + */ +public class SimpleCacheManager extends AbstractCacheManager { + + private Collection caches; + + /** + * Specify the collection of Cache instances to use for this CacheManager. + */ + public void setCaches(Collection caches) { + this.caches = caches; + } + + @Override + protected Collection loadCaches() { + return this.caches; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/ValueWrapperImpl.java b/org.springframework.context/src/main/java/org/springframework/cache/support/ValueWrapperImpl.java index ec444700a68..cc8ab88f5ee 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/ValueWrapperImpl.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/ValueWrapperImpl.java @@ -1,39 +1,39 @@ -/* - * Copyright 2002-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.support; - -import org.springframework.cache.Cache.ValueWrapper; - -/** - * Straightforward implementation of {@link org.springframework.cache.Cache.ValueWrapper}. - * - * @author Costin Leau - * @since 3.1 - */ -public class ValueWrapperImpl implements ValueWrapper { - - private final Object value; - - public ValueWrapperImpl(Object value) { - this.value = value; - } - - public Object get() { - return this.value; - } - -} +/* + * Copyright 2002-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.support; + +import org.springframework.cache.Cache.ValueWrapper; + +/** + * Straightforward implementation of {@link org.springframework.cache.Cache.ValueWrapper}. + * + * @author Costin Leau + * @since 3.1 + */ +public class ValueWrapperImpl implements ValueWrapper { + + private final Object value; + + public ValueWrapperImpl(Object value) { + this.value = value; + } + + public Object get() { + return this.value; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/cache/support/package-info.java b/org.springframework.context/src/main/java/org/springframework/cache/support/package-info.java index 852503e8f9f..38c95daf264 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/support/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/support/package-info.java @@ -1,6 +1,5 @@ -/** - * Support classes for the the org.springframework.cache package. - * Provides abstract classes for cache managers and caches. - */ -package org.springframework.cache.support; - +/** + * Support classes for the the org.springframework.cache package. + * Provides abstract classes for cache managers and caches. + */ +package org.springframework.cache.support;