SGF-528 - Enable GemfireCacheManager to explicitly specify Cache names referring to Regions that will be used in Spring's Caching Infrastructure.

(cherry picked from commit 1af7ad523ae701ccd3e4770695ce1dcc7b5e12ef)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2016-09-23 19:07:15 -07:00
parent 5c3461724f
commit 0ff21f6eef
10 changed files with 1119 additions and 350 deletions

View File

@@ -4,9 +4,11 @@ buildscript {
}
dependencies {
classpath 'io.spring.gradle:docbook-reference-plugin:0.3.0'
classpath 'io.spring.gradle:spring-io-plugin:0.0.4.RELEASE'
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.0'
classpath 'org.asciidoctor:asciidoctorj:1.5.0'
classpath 'org.springframework.build.gradle:bundlor-plugin:0.1.2'
classpath 'org.springframework.build.gradle:bundlor-plugin:0.1.3'
classpath 'org.springframework.build.gradle:propdeps-plugin:0.0.6'
classpath 'io.spring.gradle:docbook-reference-plugin:0.3.0'
classpath 'io.spring.gradle:spring-io-plugin:0.0.4.RELEASE'
@@ -33,6 +35,17 @@ archivesBaseName = project.name
sourceCompatibility = 1.6
targetCompatibility = 1.6
sourceSets {
main {
output.classesDir = 'build/classes/main'
output.resourcesDir = 'build/classes/main'
}
test {
output.classesDir = 'build/classes/test'
output.resourcesDir = 'build/classes/test'
}
}
[compileJava, compileTestJava]*.options*.compilerArgs = ["-Xlint:-serial"]
if (project.hasProperty('platformVersion')) {
@@ -68,17 +81,6 @@ tasks.withType(Test).all {
systemProperties['spring.profiles.active'] = 'apache-geode'
}
sourceSets {
main {
output.resourcesDir = 'build/classes/main'
output.classesDir = 'build/classes/main'
}
test {
output.resourcesDir = 'build/classes/test'
output.classesDir = 'build/classes/test'
}
}
repositories {
maven { url "https://repo.spring.io/libs-release" }
maven { url "https://repo.spring.io/plugins-release"}
@@ -121,13 +123,13 @@ dependencies {
testCompile("org.springframework:spring-test:$springVersion") {
exclude group: "commons-logging", module: "commons-logging"
}
testCompile "org.assertj:assertj-core:$assertjVersion"
testCompile "junit:junit:$junitVersion"
testCompile "org.apache.openwebbeans.test:cditest-owb:$openwebbeansVersion"
testCompile "org.assertj:assertj-core:$assertjVersion"
testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion"
testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
testCompile "org.mockito:mockito-core:$mockitoVersion"
testCompile "edu.umd.cs.mtc:multithreadedtc:$multiThreadedtcVersion"
testCompile "org.apache.openwebbeans.test:cditest-owb:$openwebbeansVersion"
testRuntime "javax.el:el-api:$cdiVersion"
testRuntime "javax.servlet:servlet-api:$servletApiVersion"
@@ -159,33 +161,42 @@ jar {
}
}
javadoc {
dependsOn = [ 'extractSharedResources' ]
destinationDir = file("${buildDir}/api")
ext.srcDir = file("$buildDir/shared-resources")
ext.tmpDir = file("${buildDir}/api-work")
configure(options) {
stylesheetFile = file("$buildDir/shared-resources/javadoc/spring-javadoc.css")
docFilesSubDirs = true
outputLevel = org.gradle.external.javadoc.JavadocOutputLevel.QUIET
breakIterator = true
showFromProtected()
groups = [
'Spring GemFire' : ['org.springframework.data.gemfire*'],
]
links = [
"http://docs.oracle.com/javase/6/docs/api/",
"http://docs.spring.io/spring/docs/current/javadoc-api/",
"http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/",
"http://logging.apache.org/log4j/1.2/apidocs/",
]
exclude "org/springframework/data/gemfire/config/**"
task extractSharedResources(type: Copy) {
from {
// use of closure defers evaluation until execution time
configurations.sharedResources.collect { zipTree(it) }
}
into "$buildDir/shared-resources"
}
title = "${rootProject.description} ${version} API"
javadoc {
dependsOn = [ 'extractSharedResources' ]
destinationDir = file("${buildDir}/api")
ext.tmpDir = file("${buildDir}/api-work")
configure(options) {
breakIterator = true
docFilesSubDirs = true
outputLevel = org.gradle.external.javadoc.JavadocOutputLevel.QUIET
stylesheetFile = file("$buildDir/shared-resources/javadoc/spring-javadoc.css")
showFromProtected()
groups = [
'Spring GemFire' : ['org.springframework.data.gemfire*'],
]
links = [
"http://docs.oracle.com/javase/6/docs/api/",
"http://docs.spring.io/spring/docs/current/javadoc-api/",
"http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/",
"http://logging.apache.org/log4j/1.2/apidocs/",
]
exclude "org/springframework/data/gemfire/config/**"
}
title = "${rootProject.description} ${version} API"
}
asciidoctor {
@@ -233,6 +244,31 @@ task javadocJar(type: Jar, dependsOn: javadoc) {
from javadoc
}
task docsZip(type: Zip) {
group = 'Distribution'
classifier = 'docs'
description = "Builds -${classifier} archive containing api and reference for deployment"
dependsOn = [ 'javadoc', 'asciidoctor', 'referencePdf' ]
from('docs/src/info') {
include 'changelog.txt'
}
from (javadoc) {
into 'api'
}
from (asciidoctor.outputDir) {
include "index.html"
include "spring.css"
into 'reference/html'
}
from (referencePdf.outputDir) {
into 'reference'
}
}
task schemaZip(type: Zip) {
description = "Builds -${classifier} archive containing all XSDs for deployment"
baseName = project.archivesBaseName
@@ -264,32 +300,7 @@ task schemaZip(type: Zip) {
}
}
task docsZip(type: Zip, dependsOn: [javadoc, asciidoctor, referencePdf]) {
description = "Builds -${classifier} archive containing api and reference for deployment"
baseName = project.archivesBaseName
classifier = 'docs'
group = 'Distribution'
from('src/main/resources') {
include 'changelog.txt'
}
from (javadoc) {
into 'api'
}
from (asciidoctor.outputDir) {
include "index.html"
include "spring.css"
into 'reference/html'
}
from (referencePdf.outputDir) {
into 'reference'
}
}
task distZip(type: Zip, dependsOn: [jar, sourcesJar, javadocJar, schemaZip, docsZip]) {
task distZip(type: Zip, dependsOn: [jar, docsZip, schemaZip, sourcesJar, javadocJar]) {
description = "Builds -${classifier} archive, containing all jars and docs, suitable for community download page."
baseName = project.archivesBaseName
@@ -300,6 +311,7 @@ task distZip(type: Zip, dependsOn: [jar, sourcesJar, javadocJar, schemaZip, docs
into (zipRootDir) {
from('src/main/resources') {
include 'changelog.txt'
include 'license.txt'
include 'notice.txt'
include 'readme.txt'
@@ -328,14 +340,6 @@ task distZip(type: Zip, dependsOn: [jar, sourcesJar, javadocJar, schemaZip, docs
}
}
task extractSharedResources(type: Copy) {
from { // use of closure defers evaluation until execution time
configurations.sharedResources.collect { zipTree(it) }
}
into "$buildDir/shared-resources"
}
artifacts {
archives sourcesJar
archives javadocJar

View File

@@ -1,6 +1,6 @@
antlrVersion=2.7.7
aspectjVersion=1.8.9
assertjVersion=3.5.2
assertjVersion=2.5.0
cdiVersion=1.0
gemfireVersion=1.0.0-incubating.M3
googleCodeFindbugsVersion=2.0.2
@@ -13,8 +13,8 @@ multiThreadedtcVersion=1.01
openwebbeansVersion=1.2.8
servletApiVersion=2.5
slf4jVersion=1.7.21
springVersion=4.2.8.RELEASE
spring.range="[4.0.0, 5.0.0)"
springVersion=4.3.3.RELEASE
springDataBuildVersion=1.8.3.RELEASE
springDataCommonsVersion=1.12.3.RELEASE
springShellVersion=1.1.0.RELEASE

16
pom.xml
View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.8.3.RELEASE</version>
<version>1.9.0.BUILD-SNAPSHOT</version>
</parent>
<groupId>org.springframework.data</groupId>
@@ -20,7 +20,7 @@
<properties>
<dist.key>SGF</dist.key>
<antlr.version>2.7.7</antlr.version>
<assertj.version>3.5.2</assertj.version>
<assertj.version>2.5.0</assertj.version>
<gemfire.version>1.0.0-incubating.M3</gemfire.version>
<google-code-findbugs.version>2.0.2</google-code-findbugs.version>
<multithreadedtc.version>1.01</multithreadedtc.version>
@@ -169,16 +169,16 @@
</dependency>
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>${webbeans}</version>
<groupId>org.apache.derby</groupId>
<artifactId>derbyLocale_zh_TW</artifactId>
<version>10.9.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyLocale_zh_TW</artifactId>
<version>10.9.1.0</version>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>

View File

@@ -18,18 +18,16 @@ package org.springframework.data.gemfire.support;
import java.util.concurrent.Callable;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.ObjectUtils;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;
/**
* Spring Framework {@link Cache} implementation backed by a GemFire {@link Region}.
*
* Supports GemFire 6.5 or higher.
*
* @author Costin Leau
* @author John Blum
* @author Oliver Gierke
@@ -38,58 +36,133 @@ import com.gemstone.gemfire.cache.Region;
*/
public class GemfireCache implements Cache {
@SuppressWarnings({ "rawtypes" })
private final Region region;
/**
* Creates a {@link GemFireCache} instance.
*
* @param region backing GemFire region
* Wraps a GemFire {@link Region} in an instance of {@link GemfireCache} to adapt the GemFire {@link Region}
* to function as a Spring {@link Cache} in Spring's caching infrastructure.
*
* @param region GemFire {@link Region} to wrap.
* @return an instance of {@link GemfireCache} backed by the provided GemFire {@link Region}.
* @see com.gemstone.gemfire.cache.Region
* @see org.springframework.cache.Cache
* @see #GemfireCache(Region)
*/
public GemfireCache(final Region<?, ?> region) {
public static GemfireCache wrap(Region<?, ?> region) {
return new GemfireCache(region);
}
/**
* Constructs an instance of {@link GemFireCache} initialized with the given GemFire {@link Region}.
* The {@link Region} will function as the backing store and implementation for
* the Spring {@link Cache} interface.
*
* @param region GemFire {@link Region} backing the Spring {@link Cache}.
* @throws IllegalArgumentException if {@link Region} is null.
*/
public GemfireCache(Region<?, ?> region) {
Assert.notNull(region, "GemFire Region must not be null");
this.region = region;
}
/**
* Returns the GemFire {@link Region} used as the implementation for this Spring {@link Cache}.
*
* @return the GemFire {@link Region} used as the implementation for this Spring {@link Cache}.
* @see com.gemstone.gemfire.cache.Region
*/
public Region getNativeCache() {
return this.region;
}
/**
* Returns the name of this Spring {@link Cache}.
*
* @return the name of this Spring {@link Cache}.
* @see com.gemstone.gemfire.cache.Region#getName()
*/
public String getName() {
return region.getName();
}
public Region<?, ?> getNativeCache() {
return region;
return getNativeCache().getName();
}
/**
* Clears the entire contents of this Spring {@link Cache}.
*
* @see com.gemstone.gemfire.cache.Region#clear()
*/
public void clear() {
region.clear();
getNativeCache().clear();
}
public void evict(final Object key) {
region.destroy(key);
/**
* Evicts (destroys) the entry (key/value) mapped to the given key from this Spring {@link Cache}.
*
* @param key key used to identify the cache entry to evict.
* @see com.gemstone.gemfire.cache.Region#destroy(Object)
*/
public void evict(Object key) {
getNativeCache().destroy(key);
}
public ValueWrapper get(final Object key) {
Object value = region.get(key);
/**
* Returns the cache value for the given key wrapped in an instance of
* {@link org.springframework.cache.Cache.ValueWrapper}.
*
* @param key key identifying the the value to retrieve from the cache.
* @return the value cached with the given key.
* @see org.springframework.cache.Cache.ValueWrapper
* @see com.gemstone.gemfire.cache.Region#get(Object)
*/
public ValueWrapper get(Object key) {
Object value = getNativeCache().get(key);
return (value == null ? null : new SimpleValueWrapper(value));
return (value != null ? new SimpleValueWrapper(value) : null);
}
/**
* Returns the cache value for the given key cast to the specified {@link Class} type.
*
* @param <T> desired {@link Class} type of the cache value.
* @param key key identifying the the value to retrieve from the cache.
* @param type desired {@link Class} type of the value.
* @return the cache value for the given key cast to the specified {@link Class} type.
* @throws IllegalStateException if the value is not null and not an instance of the desired type.
* @see com.gemstone.gemfire.cache.Region#get(Object)
*/
@SuppressWarnings("unchecked")
public <T> T get(final Object key, final Class<T> type) {
Object value = region.get(key);
public <T> T get(Object key, Class<T> type) {
Object value = getNativeCache().get(key);
if (value != null && type != null && !type.isInstance(value)) {
throw new IllegalStateException(String.format("Cached value is not of required type [%1$s]: %2$s",
type.getName(), value));
throw new IllegalStateException(String.format(
"Cached value [%1$s] is not an instance of type [%2$s]",
value, type.getName()));
}
return (T) value;
}
/**
* Returns the cache value for given key. If the value is {@literal null}, then the provided
* {@link Callable} {@code valueLoader} will be called to obtain a value and add the entry
* to this cache.
*
* @param <T> {@link Class} type of the value.
* @param key key identifying the the value to retrieve from the cache.
* @param valueLoader {@link Callable} object used to load a value if the entry identified by the key
* does not already have value.
* @return the cache value of the given key or a value obtained by calling the {@link Callable} object
* if the value for key is {@literal null}.
* @throws org.springframework.cache.Cache.ValueRetrievalException if an error occurs while trying to
* load a value for given key using the {@link Callable}.
* @see #get(Object, Class)
*/
@SuppressWarnings("unchecked")
public <T> T get(final Object key, final Callable<T> valueLoader) {
public <T> T get(Object key, Callable<T> valueLoader) {
T value = (T) get(key, Object.class);
if (value == null) {
synchronized (region) {
synchronized (getNativeCache()) {
value = (T) get(key, Object.class);
if (value == null) {
@@ -98,11 +171,7 @@ public class GemfireCache implements Cache {
put(key, value);
}
catch (Exception e) {
throw new RuntimeException(String.format(
"Failed to load value for key [%1$s] using valueLoader [%2$s]", key,
ObjectUtils.nullSafeClassName(valueLoader)));
//TODO throw ValueRetrievalException when SDG is based on Spring Framework 4.3
//throw new ValueRetrievalException(key, valueLoader, e);
throw new ValueRetrievalException(key, valueLoader, e);
}
}
}
@@ -111,24 +180,34 @@ public class GemfireCache implements Cache {
return value;
}
/**
* Stores the given value in the cache referenced by the given key. This operation will only store the value
* if the value is not {@literal null}.
*
* @param key key used to reference the value in the cache.
* @param value value to store in the cache referenced by the key.
* @see com.gemstone.gemfire.cache.Region#put(Object, Object)
*/
@SuppressWarnings("unchecked")
public void put(final Object key, final Object value) {
public void put(Object key, Object value) {
if (value != null) {
region.put(key, value);
getNativeCache().put(key, value);
}
}
/**
* Implementation to satisfy extension of the {@link Cache} interface in Spring 4.1. Don't add the {@link Override}
* annotation as this will break the compilation on 4.0.
*
* Implementation of {@link Cache#putIfAbsent(Object, Object)} satisfying the extension of
* the {@link Cache} interface in Spring 4.1. Don't add the {@link Override} annotation
* otherwise this will break the compilation on 4.0.
*
* @return the existing value if the given key is already mapped to a value.
* @see org.springframework.cache.Cache#putIfAbsent(java.lang.Object, java.lang.Object)
* @see com.gemstone.gemfire.cache.Region#putIfAbsent(Object, Object)
*/
@SuppressWarnings("unchecked")
public ValueWrapper putIfAbsent(Object key, Object value) {
Object existingValue = region.putIfAbsent(key, value);
Object existingValue = getNativeCache().putIfAbsent(key, value);
return (existingValue == null ? null : new SimpleValueWrapper(existingValue));
return (existingValue != null ? new SimpleValueWrapper(existingValue) : null);
}
}

View File

@@ -17,103 +17,223 @@
package org.springframework.data.gemfire.support;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.AbstractCacheManager;
import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.Region;
/**
* Spring Framework {@link CacheManager} backed by a Gemfire {@link com.gemstone.gemfire.cache.Cache}. Automatically
* discovers the created caches (or {@link Region}s in Gemfire terminology).
*
* Core Spring Framework {@link CacheManager} implementation backed by a GemFire cache instance
* (either a client or peer cache).
*
* Automatically discovers available caches (or GemFire {@link Region Regions}) when a cache for a given name
* is missing and dynamic cache lookup/creation is enabled.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.springframework.cache.Cache
* @see org.springframework.cache.CacheManager
* @see org.springframework.cache.support.AbstractCacheManager
* @see com.gemstone.gemfire.cache.Cache
* @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.Region
*/
@SuppressWarnings("unused")
public class GemfireCacheManager extends AbstractCacheManager {
private com.gemstone.gemfire.cache.Cache gemfireCache;
private final AtomicBoolean dynamic = new AtomicBoolean(true);
private Set<Region<?,?>> regions;
private com.gemstone.gemfire.cache.GemFireCache gemfireCache;
private Set<Region<?, ?>> regions;
private Set<String> cacheNames;
/* (non-Javadoc) */
@SuppressWarnings("all")
<T extends GemFireCache> T assertGemFireCacheAvailable(T gemfireCache) {
Assert.state(gemfireCache != null, "A GemFire cache instance is required");
Assert.state(!gemfireCache.isClosed(), String.format("GemFire cache [%s] has been closed",
gemfireCache.getName()));
return gemfireCache;
}
/* (non-Javadoc) */
@SuppressWarnings("all")
Region<?, ?> assertGemFireRegionAvailable(Region<?, ?> region, String cacheName) {
Assert.state(region != null, String.format("No Region for cache name [%s] was found", cacheName));
Assert.state(!region.isDestroyed(), String.format("Region [%s] has been destroyed", cacheName));
return region;
}
/**
* Loads the GemFire Cache Regions managed by this CacheManager.
* Loads all configured GemFire {@link Region Regions} that will be used by this {@link CacheManager}.
*
* @return a Collection of GemFire Cache Regions (caches) to be managed by this SDG CacheManager.
* Any GemFire {@link Region Regions} configured with the {@link #regions} property will take precedence over
* any configured {@link #cacheNames}. If no GemFire {@link Region Regions} were configured, then any
* {@link #cacheNames} that were specified will be used to lookup existing GemFire {@link Region Regions}
* to function as Spring {@link Cache Caches}in Spring's caching infrastructure.
*
* However, if neither {@link #regions} nor {@link #cacheNames} were specified, then all defined GemFire
* {@link Region Regions} declared in the Spring application context, as determined by
* {@link GemFireCache#rootRegions()}, will be used as Spring {@link Cache Caches}, and this {@link CacheManager}
* will allow any dynamically created GemFire {@link Region Regions} at runtime to be found and used as a
* Spring {@link Cache} as well.
*
* @return a {@link Collection} of GemFire {@link Region Regions} used by this {@link CacheManager}
* to function as {@link Cache Caches} in Spring's caching infrastructure.
* @throws IllegalStateException if a GemFire cache instance was not provided, the provided GemFire cache instance
* has been closed, no GemFire {@link Region} could be found for a given cache name, or the GemFire {@link Region}
* for the given cache name has been destroyed.
* @see org.springframework.cache.Cache
* @see com.gemstone.gemfire.cache.Cache#rootRegions()
*/
@Override
protected Collection<Cache> loadCaches() {
if (regions == null) {
Assert.state(gemfireCache != null, "A backing GemFire Cache is required.");
Assert.state(!gemfireCache.isClosed(), "The GemFire Cache is closed; an open instance is required.");
Set<Region<?, ?>> regions = resolveRegions(this.gemfireCache, this.regions, this.cacheNames);
regions = gemfireCache.rootRegions();
}
Collection<Cache> caches = new HashSet<Cache>(regions.size());
Collection<Cache> caches = new LinkedHashSet<Cache>(regions.size());
for (Region<?,?> region: this.regions) {
caches.add(new GemfireCache(region));
for (Region<?, ?> region : regions) {
caches.add(GemfireCache.wrap(region));
}
return caches;
}
/* (non-Javadoc) */
Set<Region<?, ?>> resolveRegions(GemFireCache gemfireCache, Set<Region<?, ?>> regions, Set<String> cacheNames) {
if (isSet(regions)) {
dynamic.set(false);
return regions;
}
else if (isSet(cacheNames)) {
dynamic.set(false);
regions = new HashSet<Region<?, ?>>(cacheNames.size());
for (String cacheName : cacheNames) {
regions.add(regionFor(gemfireCache, cacheName));
}
return regions;
}
else {
return assertGemFireCacheAvailable(gemfireCache).rootRegions();
}
}
/* (non-Javadoc) */
boolean isSet(Iterable<?> collection) {
return (collection != null && collection.iterator().hasNext());
}
/* (non-Javadoc) */
Region<?, ?> regionFor(GemFireCache gemfireCache, String cacheName) {
return assertGemFireRegionAvailable(assertGemFireCacheAvailable(gemfireCache).getRegion(cacheName), cacheName);
}
/**
* Gets a Cache (GemFire Cache Region) by name.
* Returns a missing Spring {@link Cache} for the given {@code name}.
*
* @param name a String indicating the name of the Cache to get.
* @return a Cache with the given name.
* To return a missing Spring {@link Cache} for the given {@code name}, dynamic cache lookup/creation must be
* enabled, which means that either the {@link #cacheNames} or {@link #regions} properties must not be set.
* If either property was specified then dynamic Spring {@link Cache} lookup/creation will be disabled and this
* overridden {@link AbstractCacheManager#getMissingCache(String)} method will return {@literal null}.
*
* @param name name of the missing Spring {@link Cache} to lookup (and potentially create).
* @return a Spring {@link Cache} instance for the given {@code name} or {@literal null} if the {@link Cache}
* cannot be found (or possibly created).
* @see org.springframework.cache.support.AbstractCacheManager#getMissingCache(String)
* @see org.springframework.cache.Cache
*/
@Override
public Cache getCache(String name) {
Cache cache = super.getCache(name);
protected Cache getMissingCache(String name) {
Cache cache = super.getMissingCache(name);
if (cache == null) {
// check the GemFire Cache again in case the Cache (Region) was added at runtime
Region<?, ?> region = gemfireCache.getRegion(name);
if (region != null) {
cache = new GemfireCache(region);
addCache(cache);
}
}
return cache;
return (cache != null ? cache : (isDynamic() ? GemfireCache.wrap(regionFor(this.gemfireCache, name)) : null));
}
/**
* Sets the GemFire Cache backing this {@link CacheManager}.
*
* @param gemfireCache the GemFire Peer Cache instance.
* @see com.gemstone.gemfire.cache.Cache
* Determines whether this {@link CacheManager} allows the dynamic creation of a {@link Cache} at runtime.
*
* @return a boolean value indicating whether dynamic {@link Cache} creation is enabled.
*/
public void setCache(com.gemstone.gemfire.cache.Cache gemfireCache) {
protected boolean isDynamic() {
return dynamic.get();
}
/**
* Sets the GemFire cache instance backing this {@link CacheManager}.
*
* When set, if neither {@link Region Regions} nor {@code cacheNames} were specified, then this {@link CacheManager}
* is capable of creating Spring {@link Cache Caches} backed by existing GemFire {@link Region Regions} used by
* the application at runtime. However, in order to dynamically create Spring {@link Cache Caches} a reference to
* an open GemFire cache instance must be set.
*
* @param gemfireCache the GemFire cache instance used by this {@link CacheManager}
* to manage Spring {@link Cache Caches}.
* @see com.gemstone.gemfire.cache.GemFireCache
*/
public void setCache(com.gemstone.gemfire.cache.GemFireCache gemfireCache) {
this.gemfireCache = gemfireCache;
}
/**
* Sets the Regions to use (alternative to injecting the GemFire Cache).
* Returns the {@link GemFireCache} instance backing this {@link CacheManager}.
*
* @param regions the Set of Regions (caches) managed by this CacheManager.
* @return the {@link GemFireCache} instance backing this {@link CacheManager}.
* @see com.gemstone.gemfire.cache.GemFireCache
*/
protected com.gemstone.gemfire.cache.GemFireCache getCache() {
return this.gemfireCache;
}
/**
* Sets the names of all Spring {@link Cache Caches} that will be used in the application.
*
* When set, this disables the dynamic capability of this {@link CacheManager} to create Spring {@link Cache Caches}
* at runtime by dynamically looking up existing {@link Region Regions} from the GemFire cache instance.
*
* @param cacheNames {@link Set} of cache names that will be used in the application.
* @see java.util.Set
*/
public void setCacheNames(Set<String> cacheNames) {
this.cacheNames = cacheNames;
}
/**
* Explicitly sets the GemFire {@link Region Regions} to be used as Spring {@link Cache Caches}
* in the application.
*
* When set, this disables the dynamic capability of this {@link CacheManager} to create Spring {@link Cache Caches}
* at runtime by dynamically looking up existing {@link Region Regions} from the GemFire cache instance.
*
* @param regions {@link Set} of GemFire {@link Region Regions} used by this {@link CacheManager}
* as Spring {@link Cache Caches}.
* @see com.gemstone.gemfire.cache.Region
*/
public void setRegions(Set<Region<?,?>> regions) {
public void setRegions(Set<Region<?, ?>> regions) {
this.regions = regions;
}
/**
* Returns the set of GemFire {@link Region Regions} used explicitly as Spring {@link Cache Caches}
* in Spring's caching infrastructure.
*
* @return the set of GemFire {@link Region Regions} functioning as Spring {@link Cache Caches}
* in Spring's caching infrastructure
* @see com.gemstone.gemfire.cache.Region
*/
protected Set<Region<?, ?>> getRegions() {
return this.regions;
}
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright 2010 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.data.gemfire.support;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cache.Cache;
/**
* Abstract base test class for native cache implementations.
*
* @author Costin Leau
* @author John Blum
* @see org.springframework.cache.Cache
*/
public abstract class AbstractNativeCacheTest<T> {
protected static final String CACHE_NAME = "Example";
private T nativeCache;
private Cache cache;
@Before
public void setUp() throws Exception {
nativeCache = createNativeCache();
cache = createCache(nativeCache);
cache.clear();
}
@SuppressWarnings("unchecked")
protected <C extends Cache> C createCache() throws Exception {
return (C) createCache(createNativeCache());
}
protected abstract Cache createCache(T nativeCache);
protected abstract T createNativeCache() throws Exception;
@Test
public void cacheNameIsEqualToExpected() throws Exception {
assertThat(cache.getName(), is(equalTo(CACHE_NAME)));
}
@Test
@SuppressWarnings("unchecked")
public void nativeCacheIsSameAsExpected() throws Exception {
assertThat((T) cache.getNativeCache(), is(sameInstance(nativeCache)));
}
@Test
public void cachePutIsSuccessful() throws Exception {
assertThat(cache.get("enescu"), is(nullValue()));
cache.put("enescu", "george");
assertThat(String.valueOf(cache.get("enescu").get()), is(equalTo("george")));
}
@Test
public void cacheGetForClassTypeIsSuccessful() {
cache.put("one", Boolean.TRUE);
cache.put("two", 'X');
cache.put("three", 101);
cache.put("four", Math.PI);
cache.put("five", "TEST");
assertThat(cache.get("one", Boolean.class), is(equalTo(Boolean.TRUE)));
assertThat(cache.get("two", Character.class), is(equalTo('X')));
assertThat(cache.get("three", Integer.class), is(equalTo(101)));
assertThat(cache.get("four", Double.class), is(equalTo(Math.PI)));
assertThat(cache.get("five", String.class), is(equalTo("TEST")));
}
@Test
public void cacheClearIsSuccessful() throws Exception {
assertThat(cache.get("enescu"), is(nullValue()));
cache.put("enescu", "george");
assertThat(cache.get("vlaicu"), is(nullValue()));
cache.put("vlaicu", "aurel");
assertThat(cache.get("enescu", String.class), is(equalTo("george")));
assertThat(cache.get("vlaicu", String.class), is(equalTo("aurel")));
cache.clear();
assertThat(cache.get("vlaicu"), is(nullValue()));
assertThat(cache.get("enescu"), is(nullValue()));
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2010 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.data.gemfire.support;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cache.Cache;
/**
* Abstract base test class for native cache implementations.
*
* @author Costin Leau
* @author John Blum
* @see org.junit.Test
* @see org.springframework.cache.Cache
*/
public abstract class AbstractNativeCacheTests<T> {
protected static final String CACHE_NAME = "Example";
private T nativeCache;
private Cache cache;
@Before
public void setUp() throws Exception {
nativeCache = newNativeCache();
cache = newCache(nativeCache);
cache.clear();
}
@SuppressWarnings("unchecked")
protected <C extends Cache> C newCache() throws Exception {
return (C) newCache(newNativeCache());
}
protected abstract Cache newCache(T nativeCache);
protected abstract T newNativeCache() throws Exception;
@Test
public void cacheNameIsEqualToExpected() throws Exception {
assertThat(cache.getName()).isEqualTo(CACHE_NAME);
}
@Test
public void nativeCacheIsSameAsExpected() throws Exception {
assertThat(cache.getNativeCache()).isSameAs(nativeCache);
}
@Test
public void cachePutIsSuccessful() throws Exception {
assertThat(cache.get("enescu")).isNull();
cache.put("enescu", "george");
assertThat(cache.get("enescu").get()).isEqualTo("george");
}
@Test
public void cachePutThenClearIsSuccessful() throws Exception {
cache.put("enescu", "george");
cache.put("vlaicu", "aurel");
assertThat(cache.get("enescu", String.class)).isEqualTo("george");
assertThat(cache.get("vlaicu", String.class)).isEqualTo("aurel");
cache.clear();
assertThat(cache.get("vlaicu")).isNull();
assertThat(cache.get("enescu")).isNull();
}
@Test
public void cachePutThenGetForClassTypeIsSuccessful() {
cache.put("one", Boolean.TRUE);
cache.put("two", 'X');
cache.put("three", 101);
cache.put("four", Math.PI);
cache.put("five", "TEST");
assertThat(cache.get("one", Boolean.class)).isTrue();
assertThat(cache.get("two", Character.class)).isEqualTo('X');
assertThat(cache.get("three", Integer.class)).isEqualTo(101);
assertThat(cache.get("four", Double.class)).isEqualTo(Math.PI);
assertThat(cache.get("five", String.class)).isEqualTo("TEST");
}
}

View File

@@ -16,13 +16,18 @@
package org.springframework.data.gemfire.support;
import static org.hamcrest.Matchers.equalTo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import edu.umd.cs.mtc.MultithreadedTestCase;
import edu.umd.cs.mtc.TestFramework;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.Region;
import org.junit.Rule;
import org.junit.Test;
@@ -30,42 +35,35 @@ import org.junit.rules.ExpectedException;
import org.springframework.cache.Cache;
import org.springframework.data.gemfire.GemfireUtils;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.Region;
import edu.umd.cs.mtc.MultithreadedTestCase;
import edu.umd.cs.mtc.TestFramework;
/**
* Tests the interaction between the Spring Framework Cache Abstraction and GemFire as a provider
* using Spring Data GemFire's extension.
* Integration Tests for {@link GemfireCache}.
*
* @author Costin Leau
* @author John Blum
* @author Oliver Gierke
* @see org.junit.Rule
* @see org.junit.Test
* @see edu.umd.cs.mtc.MultithreadedTestCase
* @see edu.umd.cs.mtc.TestFramework
* @see org.springframework.cache.Cache
* @see com.gemstone.gemfire.cache.Region
*/
public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Object>> {
public class GemfireCacheIntegrationTests extends AbstractNativeCacheTests<Region<Object, Object>> {
@Rule
public ExpectedException expectedException = ExpectedException.none();
public ExpectedException exception = ExpectedException.none();
@Override
protected Cache createCache(Region<Object, Object> nativeCache) {
protected Cache newCache(Region<Object, Object> nativeCache) {
return new GemfireCache(nativeCache);
}
@Override
protected Region<Object, Object> createNativeCache() throws Exception {
protected Region<Object, Object> newNativeCache() throws Exception {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", GemfireCacheTest.class.getName());
gemfireProperties.setProperty("name", GemfireCacheIntegrationTests.class.getName());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("locators", "");
gemfireProperties.setProperty("log-level", "warning");
com.gemstone.gemfire.cache.Cache cache = GemfireUtils.getCache();
@@ -84,11 +82,11 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
*/
@Test
public void findsTypedValue() throws Exception {
Cache cache = createCache();
Cache cache = newCache();
cache.put("key", "value");
assertThat(cache.get("key", String.class), is("value"));
assertThat(cache.get("key", String.class)).isEqualTo("value");
}
/**
@@ -96,11 +94,11 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
*/
@Test
public void skipTypeChecksIfTargetTypeIsNull() throws Exception {
Cache cache = createCache();
Cache cache = newCache();
cache.put("key", "value");
cache.put("key", 1);
assertThat(cache.get("key", (Class<String>) null), is("value"));
assertThat(cache.get("key", (Class<?>) null)).isEqualTo(1);
}
/**
@@ -108,63 +106,67 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
*/
@Test
public void throwsIllegalStateExceptionIfTypedAccessDoesNotFindMatchingType() throws Exception {
Cache cache = createCache();
Cache cache = newCache();
cache.put("key", "value");
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(Integer.class.getName());
expectedException.expectMessage("value");
exception.expect(IllegalStateException.class);
exception.expectMessage(Integer.class.getName());
exception.expectMessage(String.format("Cached value [value] is not an instance of type [%s]",
Integer.class.getName()));
cache.get("key", Integer.class);
}
@Test
public void cacheGetWithValueLoaderFindsValue() throws Exception {
GemfireCache cache = createCache();
GemfireCache cache = newCache();
cache.put("key", "value");
assertThat(String.valueOf(cache.get("key", TestCacheLoader.NULL_VALUE)), is(equalTo("value")));
assertThat(TestCacheLoader.NULL_VALUE.wasCalled(), is(false));
assertThat(cache.get("key", TestValueLoader.NULL_VALUE)).isEqualTo("value");
assertThat(TestValueLoader.NULL_VALUE.wasCalled()).isFalse();
}
@Test
@SuppressWarnings("unchecked")
public void cacheGetWithValueLoaderUsesValueLoader() throws Exception {
GemfireCache cache = createCache();
public void cacheGetWithValueLoaderUsesValueLoaderReturnsValue() throws Exception {
GemfireCache cache = newCache();
TestCacheLoader<String> cacheLoader = new TestCacheLoader<String>("test");
TestValueLoader<String> valueLoader = new TestValueLoader<String>("test");
assertThat(cache.get("key", cacheLoader), is(equalTo("test")));
assertThat(cacheLoader.wasCalled(), is(true));
assertThat(((Region<Object, String>) cache.getNativeCache()).get("key"), is(equalTo("test")));
assertThat(cache.get("key", valueLoader)).isEqualTo("test");
assertThat(valueLoader.wasCalled()).isTrue();
assertThat(((Region<Object, String>) cache.getNativeCache()).get("key")).isEqualTo("test");
}
@Test
@SuppressWarnings("unchecked")
public void cacheGetWithValueLoaderUsesValueLoaderReturningNull() throws Exception {
GemfireCache cache = createCache();
public void cacheGetWithValueLoaderUsesValueLoaderReturnsNull() throws Exception {
GemfireCache cache = newCache();
assertThat(cache.get("key", TestCacheLoader.NULL_VALUE), is(nullValue()));
assertThat(TestCacheLoader.NULL_VALUE.wasCalled(), is(true));
assertThat(cache.getNativeCache().containsKey("key"), is(false));
assertThat(cache.get("key", TestValueLoader.NULL_VALUE)).isNull();
assertThat(TestValueLoader.NULL_VALUE.wasCalled()).isTrue();
assertThat(cache.getNativeCache().containsKey("key")).isFalse();
}
@Test
@SuppressWarnings("all")
public void cacheGetWithValueLoaderUsesValueLoaderThrowingException() throws Exception {
GemfireCache cache = createCache();
public void cacheGetWithValueLoaderUsesValueLoaderAndThrowsException() throws Exception {
GemfireCache cache = newCache();
TestCacheLoader<Exception> exceptionThrowingCacheLoader = new TestCacheLoader<Exception>(
new IllegalStateException("test"));
try {
TestValueLoader<Exception> exceptionThrowingValueLoader = new TestValueLoader<Exception>(
new IllegalStateException("test"));
expectedException.expect(RuntimeException.class);
expectedException.expectCause(is(nullValue(IllegalStateException.class)));
expectedException.expectMessage(String.format("Failed to load value for key [key] using valueLoader [%1$s]",
exceptionThrowingCacheLoader.getClass().getName()));
exception.expect(Cache.ValueRetrievalException.class);
exception.expectCause(is(IllegalStateException.class));
cache.get("key", exceptionThrowingCacheLoader);
cache.get("key", exceptionThrowingValueLoader);
}
finally {
assertThat(cache.getNativeCache().containsKey("key")).isFalse();
}
}
@Test
@@ -177,15 +179,15 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
private GemfireCache cache;
private TestCacheLoader<String> cacheLoader;
private TestValueLoader<String> cacheLoader;
@Override
public void initialize(){
super.initialize();
cache = createCacheHandlesCheckedException();
cache = newCacheHandlesCheckedException();
cacheLoader = new TestCacheLoader<String>("test") {
cacheLoader = new TestValueLoader<String>("test") {
@Override public String call() throws Exception {
waitForTick(2);
return super.call();
@@ -193,12 +195,12 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
};
}
<T extends Cache> T createCacheHandlesCheckedException() {
<T extends Cache> T newCacheHandlesCheckedException() {
try {
return createCache();
return newCache();
}
catch (Exception e) {
throw new RuntimeException("failed to create Cache", e);
throw new RuntimeException("Failed to create Cache", e);
}
}
@@ -210,8 +212,8 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
String value = cache.get("key", cacheLoader);
assertTick(2);
assertThat(value, is(equalTo("test")));
assertThat(cacheLoader.wasCalled(), is(true));
assertThat(value).isEqualTo("test");
assertThat(cacheLoader.wasCalled()).isTrue();
}
public void thread2() {
@@ -219,41 +221,39 @@ public class GemfireCacheTest extends AbstractNativeCacheTest<Region<Object, Obj
Thread.currentThread().setName("Cache Reader Thread");
TestCacheLoader<String> illegalCacheLoader = new TestCacheLoader<String>("illegal");
TestValueLoader<String> illegalCacheLoader = new TestValueLoader<String>("illegal");
String value = cache.get("key", illegalCacheLoader);
assertTick(2);
assertThat(value, is(equalTo("test")));
assertThat(illegalCacheLoader.wasCalled(), is(false));
assertThat(value).isEqualTo("test");
assertThat(illegalCacheLoader.wasCalled()).isFalse();
}
}
protected static class TestCacheLoader<T> implements Callable<T> {
protected static class TestValueLoader<T> implements Callable<T> {
protected static final TestCacheLoader<Object> NULL_VALUE = new TestCacheLoader<Object>();
protected static final TestValueLoader<Object> NULL_VALUE = new TestValueLoader<Object>();
private volatile boolean called;
private AtomicBoolean called = new AtomicBoolean(false);
private final T value;
public TestCacheLoader() {
public TestValueLoader() {
this(null);
}
public TestCacheLoader(T value) {
public TestValueLoader(T value) {
this.value = value;
}
protected boolean wasCalled() {
boolean called = this.called;
this.called = false;
return called;
return called.compareAndSet(true, false);
}
@Override
public T call() throws Exception {
called = true;
called.set(true);
if (value instanceof Exception) {
throw (Exception) value;

View File

@@ -0,0 +1,326 @@
/*
* Copyright 2012 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.data.gemfire.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cache.Cache;
/**
* Unit tests for {@link GemfireCacheManager}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.runners.MockitoJUnitRunner
* @since 1.9.0
*/
@RunWith(MockitoJUnitRunner.class)
public class GemfireCacheManagerUnitTests {
@Rule
public ExpectedException exception = ExpectedException.none();
@Mock
private GemFireCache mockGemFireCache;
private GemfireCacheManager cacheManager;
@Mock
private Region mockRegion;
@Before
public void setup() {
cacheManager = new GemfireCacheManager();
}
protected <T> Set<T> asSet(T... elements) {
Set<T> set = new HashSet<T>(elements.length);
Collections.addAll(set, elements);
return set;
}
@SuppressWarnings("unchecked")
protected Region<?, ?> mockRegion(String name) {
Region<?, ?> mockRegion = mock(Region.class, name);
when(mockRegion.getName()).thenReturn(name);
return mockRegion;
}
protected Region<?, ?> regionFor(Iterable<Region<?, ?>> regions, String name) {
for (Region<?, ?> region : regions) {
if (region.getName().equals(name)) {
return region;
}
}
return null;
}
@Test
public void assertGemFireCacheAvailableWithAvailableGemFireCacheIsSuccessful() {
when(mockGemFireCache.isClosed()).thenReturn(false);
assertThat(cacheManager.assertGemFireCacheAvailable(mockGemFireCache)).isSameAs(mockGemFireCache);
verify(mockGemFireCache, times(1)).isClosed();
verify(mockGemFireCache, times(1)).getName();
}
@Test
public void assertGemFireCacheAvailableWithNullThrowsIllegalStateException() {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("A GemFire cache instance is required")));
cacheManager.assertGemFireCacheAvailable(null);
}
@Test
public void assertGemFireCacheAvailableWithNamedClosedGemFireCacheThrowsIllegalStateException() {
when(mockGemFireCache.isClosed()).thenReturn(true);
when(mockGemFireCache.getName()).thenReturn("Example");
try {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("GemFire cache [Example] has been closed")));
cacheManager.assertGemFireCacheAvailable(mockGemFireCache);
}
finally {
verify(mockGemFireCache,times(1)).isClosed();
verify(mockGemFireCache, times(1)).getName();
}
}
@Test
public void assertGemFireRegionAvailableWithAvailableGemFireRegionIsSuccessful() {
when(mockRegion.isDestroyed()).thenReturn(false);
assertThat(cacheManager.assertGemFireRegionAvailable(mockRegion, "Example")).isSameAs(mockRegion);
verify(mockRegion, times(1)).isDestroyed();
}
@Test
public void assertGemFireRegionAvailableWithNullThrowIllegalStateException() {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("No Region for cache name [Example] was found")));
cacheManager.assertGemFireRegionAvailable(null, "Example");
}
@Test
public void assertGemFireRegionAvailableWithDestroyedGemFireRegionThrowIllegalStateException() {
when(mockRegion.isDestroyed()).thenReturn(true);
try {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("Region [Example] has been destroyed")));
cacheManager.assertGemFireRegionAvailable(mockRegion, "Example");
}
finally {
verify(mockRegion, times(1)).isDestroyed();
}
}
@Test
@SuppressWarnings("unchecked")
public void loadCachesIsSuccessful() {
Set<Region<?, ?>> regions = asSet(mockRegion("one"), mockRegion("two"), mockRegion("three"));
cacheManager.setRegions(regions);
Collection<Cache> loadedCaches = cacheManager.loadCaches();
assertThat(loadedCaches).isNotNull();
assertThat(loadedCaches.size()).isEqualTo(3);
for (Cache cache : loadedCaches) {
assertThat(cache).isInstanceOf(GemfireCache.class);
assertThat(regionFor(regions, cache.getName())).isSameAs(cache.getNativeCache());
}
}
@Test
public void resolveRegionsReturnsGivenRegions() {
Set<Region<?, ?>> regions = asSet(mockRegion("one"), mockRegion("two"));
assertThat(cacheManager.resolveRegions(mockGemFireCache, regions, asSet("three", "four"))).isSameAs(regions);
assertThat(cacheManager.isDynamic()).isFalse();
verify(mockGemFireCache, never()).getRegion(anyString());
verify(mockGemFireCache, never()).rootRegions();
}
@Test
@SuppressWarnings("unchecked")
public void resolveRegionsReturnsRegionsForCacheNamesOnly() {
Region mockRegionOne = mockRegion("one");
Region mockRegionTwo = mockRegion("two");
Region mockRegionThree = mockRegion("three");
when(mockGemFireCache.getRegion(eq("one"))).thenReturn(mockRegionOne);
when(mockGemFireCache.getRegion(eq("two"))).thenReturn(mockRegionTwo);
when(mockGemFireCache.getRegion(eq("three"))).thenReturn(mockRegionThree);
Set<Region<?, ?>> regions = cacheManager.resolveRegions(mockGemFireCache, null, asSet("one", "two"));
assertThat(regions).isNotNull();
assertThat(regions.size()).isEqualTo(2);
assertThat(regions).containsAll(this.<Region<?, ?>>asSet(mockRegionOne, mockRegionTwo));
assertThat(cacheManager.isDynamic()).isFalse();
verify(mockGemFireCache, times(1)).getRegion(eq("one"));
verify(mockGemFireCache, times(1)).getRegion(eq("two"));
verify(mockGemFireCache, never()).getRegion(eq("three"));
}
@Test
public void resolveRegionsReturnsGemFireCacheRootRegions() {
Set<Region<?, ?>> rootRegions = asSet(mockRegion("one"), mockRegion("two"));
when(mockGemFireCache.rootRegions()).thenReturn(rootRegions);
assertThat(cacheManager.resolveRegions(mockGemFireCache, null, null)).isSameAs(rootRegions);
assertThat(cacheManager.isDynamic()).isTrue();
verify(mockGemFireCache, times(1)).rootRegions();
verify(mockGemFireCache, never()).getRegion(anyString());
}
@Test
public void isSetForNonNullNonEmptyIterableIsTrue() {
assertThat(cacheManager.isSet(Collections.singleton(1))).isTrue();
}
@Test
public void isSetForNullIterableIsFalse() {
assertThat(cacheManager.isSet(null)).isFalse();
}
@Test
public void isSetForEmptyIterableIsFalse() {
assertThat(cacheManager.isSet(Collections.emptyList())).isFalse();
}
@Test
@SuppressWarnings("unchecked")
public void regionForCacheNameReturnsRegion() {
when(mockGemFireCache.isClosed()).thenReturn(false);
when(mockGemFireCache.getName()).thenReturn("regionForCacheNameReturnsRegion");
when(mockGemFireCache.getRegion(eq("Example"))).thenReturn(mockRegion);
when(mockRegion.isDestroyed()).thenReturn(false);
assertThat(cacheManager.regionFor(mockGemFireCache, "Example")).isSameAs(mockRegion);
verify(mockGemFireCache, times(1)).isClosed();
verify(mockGemFireCache, times(1)).getName();
verify(mockGemFireCache, times(1)).getRegion(eq("Example"));
verify(mockRegion, times(1)).isDestroyed();
}
@Test
@SuppressWarnings("unchecked")
public void getMissingCacheReturnsMissingCache() {
Region mockRegion = mockRegion("missing");
when(mockGemFireCache.getRegion(eq("missing"))).thenReturn(mockRegion);
cacheManager.setCache(mockGemFireCache);
Cache cache = cacheManager.getMissingCache("missing");
assertThat(cache).isNotNull();
assertThat(cache.getNativeCache()).isEqualTo(mockRegion);
verify(mockGemFireCache, times(1)).getRegion(eq("missing"));
}
@Test
public void getMissingCacheReturnsNull() {
cacheManager.setRegions(Collections.<Region<?, ?>>singleton(mockRegion("one")));
cacheManager.afterPropertiesSet();
assertThat(cacheManager.isDynamic()).isFalse();
assertThat(cacheManager.getMissingCache("missing")).isNull();
}
@Test
public void setAndGetCache() {
assertThat(cacheManager.getCache()).isNull();
cacheManager.setCache(mockGemFireCache);
assertThat(cacheManager.getCache()).isSameAs(mockGemFireCache);
cacheManager.setCache(null);
assertThat(cacheManager.getCache()).isNull();
}
@Test
public void setAndGetCacheNames() {
Set<Region<?, ?>> regions = asSet(mockRegion("one"), mockRegion("two"));
cacheManager.setRegions(regions);
cacheManager.afterPropertiesSet();
assertThat(cacheManager.getCacheNames()).containsAll(asSet("one", "two"));
}
@Test
public void setAndGetRegions() {
Set<Region<?, ?>> regions = asSet(mockRegion("one"), mockRegion("two"));
assertThat(cacheManager.getRegions()).isNull();
cacheManager.setRegions(regions);
assertThat(cacheManager.getRegions()).isSameAs(regions);
cacheManager.setRegions(null);
assertThat(cacheManager.getRegions()).isNull();
}
}

View File

@@ -0,0 +1,248 @@
/*
* Copyright 2012 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.data.gemfire.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isA;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.concurrent.Callable;
import com.gemstone.gemfire.cache.Region;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cache.Cache;
/**
* Unit tests for {@link GemfireCache}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.runners.MockitoJUnitRunner
* @see org.springframework.data.gemfire.support.GemfireCache
* @see com.gemstone.gemfire.cache.Region
* @since 1.9.0
*/
@RunWith(MockitoJUnitRunner.class)
public class GemfireCacheUnitTests {
@Rule
public ExpectedException exception = ExpectedException.none();
@Mock
private Callable mockCallable;
@Mock
private Region mockRegion;
@Test
public void wrapIsSuccessful() {
GemfireCache gemfireCache = GemfireCache.wrap(mockRegion);
assertThat(gemfireCache).isNotNull();
assertThat(gemfireCache.getNativeCache()).isEqualTo(mockRegion);
}
@Test
public void constructGemfireCacheWithNullRegion() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(is(equalTo("GemFire Region must not be null")));
new GemfireCache(null);
}
@Test
public void getNameReturnsRegionName() {
when(mockRegion.getName()).thenReturn("Example");
assertThat(GemfireCache.wrap(mockRegion).getName()).isEqualTo("Example");
verify(mockRegion, times(1)).getName();
}
@Test
public void clearCallsRegionClear() {
GemfireCache.wrap(mockRegion).clear();
verify(mockRegion, times(1)).clear();
}
@Test
public void evictCallsRegionDestoryWithKey() {
GemfireCache.wrap(mockRegion).evict("key");
verify(mockRegion, times(1)).destroy(eq("key"));
}
@Test
public void getReturnsValueWrapperForKey() {
when(mockRegion.get(eq("key"))).thenReturn("test");
Cache.ValueWrapper value = GemfireCache.wrap(mockRegion).get("key");
assertThat(value).isNotNull();
assertThat(value.get()).isEqualTo("test");
verify(mockRegion, times(1)).get(eq("key"));
}
@Test
public void getReturnsNullForKey() {
when(mockRegion.get(anyString())).thenReturn(null);
assertThat(GemfireCache.wrap(mockRegion).get("key")).isNull();
verify(mockRegion, times(1)).get(eq("key"));
}
@Test
public void getReturnsValueForKeyAsDesiredType() {
when(mockRegion.get(eq("key"))).thenReturn(1);
Object value = GemfireCache.wrap(mockRegion).get("key", Integer.class);
assertThat(value).isNotNull();
assertThat(value).isInstanceOf(Integer.class);
assertThat(value).isEqualTo(1);
verify(mockRegion, times(1)).get(eq("key"));
}
@Test
public void getReturnsNullForKeyAsDesiredType() {
when(mockRegion.get(eq("key"))).thenReturn(null);
assertThat(GemfireCache.wrap(mockRegion).get("key", Double.class)).isNull();
verify(mockRegion, times(1)).get(eq("key"));
}
@Test
public void getReturnsValueForKeyWithNullDesiredType() {
when(mockRegion.get(eq("key"))).thenReturn(true);
assertThat(GemfireCache.wrap(mockRegion).get("key", (Class<Boolean>) null)).isTrue();
verify(mockRegion, times(1)).get(eq("key"));
}
@Test
public void getThrowsIllegalStateExceptionForKeyWhenValueIsNotAnInstanceOfDesiredType() {
when(mockRegion.get(eq("key"))).thenReturn(1);
try {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(String.format("Cached value [1] is not an instance of type [%s]",
Boolean.class.getName()));
GemfireCache.wrap(mockRegion).get("key", Boolean.class);
}
finally {
verify(mockRegion, times(1)).get(eq("key"));
}
}
@Test
public void getReturnsValueFromCacheForKeyWithValueLoader() {
when(mockRegion.get(eq("key"))).thenReturn("test");
assertThat(GemfireCache.wrap(mockRegion).get("key", mockCallable)).isEqualTo("test");
verify(mockRegion, times(1)).get(eq("key"));
verifyZeroInteractions(mockCallable);
}
@Test
public void getReturnsValueFromCacheForKeyAfterSynchronizationWithValueLoader() {
when(mockRegion.get(eq("key"))).thenReturn(null).thenReturn("test");
assertThat(GemfireCache.wrap(mockRegion).get("key", mockCallable)).isEqualTo("test");
verify(mockRegion, times(2)).get(eq("key"));
verifyZeroInteractions(mockCallable);
}
@Test
public void getReturnsValueFromValueLoaderForKeyWithValueLoader() throws Exception {
when(mockRegion.get(anyString())).thenReturn(null);
when(mockCallable.call()).thenReturn("mockValue");
assertThat(GemfireCache.wrap(mockRegion).get("key", mockCallable)).isEqualTo("mockValue");
verify(mockRegion, times(2)).get(eq("key"));
verify(mockCallable, times(1)).call();
}
@Test
public void getThrowsValueRetrievalExceptionForKeyWithValueLoader() throws Exception {
when(mockRegion.get(anyString())).thenReturn(null);
when(mockCallable.call()).thenThrow(new IllegalStateException("test"));
try {
exception.expect(Cache.ValueRetrievalException.class);
exception.expectCause(isA(IllegalStateException.class));
GemfireCache.wrap(mockRegion).get("key", mockCallable);
}
finally {
verify(mockRegion, times(2)).get(eq("key"));
verify(mockCallable, times(1)).call();
}
}
@Test
@SuppressWarnings("unchecked")
public void putCachesValue() {
GemfireCache.wrap(mockRegion).put("key", "test");
verify(mockRegion, times(1)).put(eq("key"), eq("test"));
}
@Test
@SuppressWarnings("unchecked")
public void putDoesNotCacheNull() {
GemfireCache.wrap(mockRegion).put("key", null);
verify(mockRegion, never()).put(anyString(), anyObject());
}
@Test
@SuppressWarnings("unchecked")
public void putIfAbsentReturnsExistingValue() {
when(mockRegion.putIfAbsent(eq("key"), anyObject())).thenReturn("test");
Cache.ValueWrapper value = GemfireCache.wrap(mockRegion).putIfAbsent("key", "mockValue");
assertThat(value).isNotNull();
assertThat(value.get()).isEqualTo("test");
verify(mockRegion, times(1)).putIfAbsent(eq("key"), eq("mockValue"));
}
@Test
@SuppressWarnings("unchecked")
public void putIfAbsentReturnsNull() {
when(mockRegion.putIfAbsent(eq("key"), anyObject())).thenReturn(null);
Cache.ValueWrapper value = GemfireCache.wrap(mockRegion).putIfAbsent("key", "mockValue");
assertThat(value).isNull();
verify(mockRegion, times(1)).putIfAbsent(eq("key"), eq("mockValue"));
}
}