diff --git a/build.gradle b/build.gradle
index ec87548a..79b5409a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,12 +4,12 @@ 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.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'
}
}
@@ -32,6 +32,17 @@ group = 'org.springframework.data'
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')) {
@@ -66,17 +77,6 @@ tasks.withType(Test).all {
System.getProperty('org.springframework.data.gemfire.test.GemfireTestRunner.nomock')
}
-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-snapshot" }
maven { url "https://repo.spring.io/plugins-release"}
@@ -98,12 +98,11 @@ dependencies {
// GemFire
compile("com.gemstone.gemfire:gemfire:$gemfireVersion")
- optional("com.google.code.findbugs:annotations:2.0.2")
+ optional("com.google.code.findbugs:annotations:$googleCodeFindbugsVersion")
runtime("antlr:antlr:$antlrVersion")
optional "javax.enterprise:cdi-api:$cdiVersion"
compile "org.aspectj:aspectjweaver:$aspectjVersion"
- compile "com.fasterxml.jackson.core:jackson-core:$jacksonVersion"
compile "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
@@ -111,13 +110,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"
testCompile "javax.annotation:jsr250-api:1.0", optional
testRuntime "javax.el:el-api:$cdiVersion"
@@ -125,7 +124,7 @@ dependencies {
testRuntime "log4j:log4j:$log4jVersion"
testRuntime "org.apache.derby:derbyLocale_zh_TW:10.9.1.0"
testRuntime "org.slf4j:slf4j-log4j12:$slf4jVersion"
- testRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
+ testRuntime "org.springframework.shell:spring-shell:$springShellVersion"
sharedResources "org.springframework.data.build:spring-data-build-resources:$springDataBuildVersion@zip"
}
@@ -146,11 +145,18 @@ jar {
}
}
+task extractSharedResources(type: Copy) {
+ from {
+ // use of closure defers evaluation until execution time
+ configurations.sharedResources.collect { zipTree(it) }
+ }
+ into "$buildDir/shared-resources"
+}
+
javadoc {
dependsOn = [ 'extractSharedResources' ]
destinationDir = file("${buildDir}/api")
- ext.srcDir = file("${projectDir}/docs/src/api")
ext.tmpDir = file("${buildDir}/api-work")
configure(options) {
@@ -219,33 +225,6 @@ task javadocJar(type: Jar) {
from javadoc
}
-task schemaZip(type: Zip) {
- group = 'Distribution'
- classifier = 'schema'
- description = "Builds -${classifier} archive containing all XSDs for deployment"
-
- def Properties schemas = new Properties();
-
- sourceSets.main.resources.find {
- it.path.endsWith('META-INF' + File.separator + 'spring.schemas')
- }?.withInputStream { schemas.load(it) }
-
- for (def key : schemas.keySet()) {
- def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
- def alias = key.replaceAll(/http.*schema.(.*).(spring-.*)/, '$2')
- assert shortName != key
- File xsdFile = sourceSets.main.resources.find {
- it.path.replace('\\', '/').endsWith(schemas.get(key))
- }
- assert xsdFile != null
-
- into (shortName) {
- from xsdFile.path
- rename { String fileName -> alias }
- }
- }
-}
-
task docsZip(type: Zip) {
group = 'Distribution'
classifier = 'docs'
@@ -271,6 +250,35 @@ task docsZip(type: Zip) {
}
}
+task schemaZip(type: Zip) {
+ group = 'Distribution'
+ classifier = 'schema'
+ description = "Builds -${classifier} archive containing all XSDs for deployment"
+
+ def Properties schemas = new Properties();
+
+ sourceSets.main.resources.find {
+ it.path.endsWith('META-INF' + File.separator + 'spring.schemas')
+ }?.withInputStream { schemas.load(it) }
+
+ for (def key : schemas.keySet()) {
+ def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
+ def alias = key.replaceAll(/http.*schema.(.*).(spring-.*)/, '$2')
+
+ assert shortName != key
+
+ File xsdFile = sourceSets.main.resources.find {
+ it.path.replace('\\', '/').endsWith(schemas.get(key))
+ }
+
+ assert xsdFile != null
+
+ into (shortName) {
+ from xsdFile.path
+ rename { String fileName -> alias }
+ }
+ }
+}
task distZip(type: Zip, dependsOn: [jar, docsZip, schemaZip, sourcesJar, javadocJar]) {
description = "Builds -${classifier} archive, containing all jars and docs, suitable for community download page."
@@ -280,10 +288,11 @@ task distZip(type: Zip, dependsOn: [jar, docsZip, schemaZip, sourcesJar, javadoc
ext.zipRootDir = "${project.name}-${project.version}"
into (zipRootDir) {
- from('docs/src/info') {
- include 'readme.txt'
+ from('src/main/resources') {
+ include 'changelog.txt'
include 'license.txt'
include 'notice.txt'
+ include 'readme.txt'
expand(copyright: new Date().format('yyyy'), version: project.version)
}
from('samples/') {
@@ -306,14 +315,6 @@ task distZip(type: Zip, dependsOn: [jar, docsZip, schemaZip, sourcesJar, javadoc
}
}
-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
diff --git a/gradle.properties b/gradle.properties
index 4e0e1b4a..b6dbd447 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,19 +1,21 @@
antlrVersion=2.7.7
-aspectjVersion=1.8.5
-assertjVersion=3.5.2
+aspectjVersion=1.8.9
+assertjVersion=2.5.0
cdiVersion=1.0
gemfireVersion=8.2.1
+googleCodeFindbugsVersion=2.0.2
hamcrestVersion=1.3
-jacksonVersion=2.6.0
+jacksonVersion=2.8.1
junitVersion=4.12
log4jVersion=1.2.17
mockitoVersion=1.10.19
multiThreadedtcVersion=1.01
openwebbeansVersion=1.2.8
servletApiVersion=2.5
-slf4jVersion=1.7.12
+slf4jVersion=1.7.21
spring.range="[4.0.0, 5.0.0)"
-springVersion=4.2.5.RELEASE
+springVersion=4.3.3.RELEASE
springDataBuildVersion=1.9.0.BUILD-SNAPSHOT
springDataCommonsVersion=1.13.0.BUILD-SNAPSHOT
+springShellVersion=1.0.0.RELEASE
version=1.9.0.BUILD-SNAPSHOT
diff --git a/pom.xml b/pom.xml
index ef3bb353..e0a69ad7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,28 +3,43 @@
4.0.0
- org.springframework.data
- spring-data-gemfire
- 1.9.0.BUILD-SNAPSHOT
-
- Spring Data Gemfire
-
org.springframework.data.buildspring-data-parent1.9.0.BUILD-SNAPSHOT
+ org.springframework.data
+ spring-data-gemfire
+ 1.9.0.BUILD-SNAPSHOT
+
+ Spring Data Gemfire
+
SGF2.7.7
- 3.5.2
- 8.2.0
+ 2.5.0
+ 8.2.1
+ 2.0.21.012.51.13.0.BUILD-SNAPSHOT
+
+
+ spring-libs-snapshot
+ https://repo.spring.io/libs-snapshot
+
+
+
+
+
+ spring-plugins-release
+ https://repo.spring.io/plugins-release
+
+
+
@@ -67,7 +82,7 @@
com.google.code.findbugsannotations
- 2.0.2
+ ${google-code-findbugs.version}true
@@ -121,16 +136,16 @@
- org.apache.openwebbeans.test
- cditest-owb
- ${webbeans}
+ org.apache.derby
+ derbyLocale_zh_TW
+ 10.9.1.0test
- org.apache.derby
- derbyLocale_zh_TW
- 10.9.1.0
+ org.apache.openwebbeans.test
+ cditest-owb
+ ${webbeans}test
@@ -201,18 +216,4 @@
-
-
- spring-libs-snapshot
- https://repo.spring.io/libs-snapshot
-
-
-
-
-
- spring-plugins-release
- https://repo.spring.io/plugins-release
-
-
-
diff --git a/src/main/java/org/springframework/data/gemfire/support/GemfireCache.java b/src/main/java/org/springframework/data/gemfire/support/GemfireCache.java
index d8bb1478..5287387a 100644
--- a/src/main/java/org/springframework/data/gemfire/support/GemfireCache.java
+++ b/src/main/java/org/springframework/data/gemfire/support/GemfireCache.java
@@ -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 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 get(final Object key, final Class type) {
- Object value = region.get(key);
+ public T get(Object key, Class 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 {@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 get(final Object key, final Callable valueLoader) {
+ public T get(Object key, Callable 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);
}
-
}
diff --git a/src/main/java/org/springframework/data/gemfire/support/GemfireCacheManager.java b/src/main/java/org/springframework/data/gemfire/support/GemfireCacheManager.java
index c58e6524..cf854628 100644
--- a/src/main/java/org/springframework/data/gemfire/support/GemfireCacheManager.java
+++ b/src/main/java/org/springframework/data/gemfire/support/GemfireCacheManager.java
@@ -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> regions;
+ private com.gemstone.gemfire.cache.GemFireCache gemfireCache;
+
+ private Set> regions;
+
+ private Set cacheNames;
+
+ /* (non-Javadoc) */
+ @SuppressWarnings("all")
+ 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 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> regions = resolveRegions(this.gemfireCache, this.regions, this.cacheNames);
- regions = gemfireCache.rootRegions();
- }
+ Collection caches = new HashSet(regions.size());
- Collection caches = new LinkedHashSet(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> resolveRegions(GemFireCache gemfireCache, Set> regions, Set cacheNames) {
+ if (isSet(regions)) {
+ dynamic.set(false);
+ return regions;
+ }
+ else if (isSet(cacheNames)) {
+ dynamic.set(false);
+
+ regions = new HashSet>(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 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> regions) {
+ public void setRegions(Set> 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> getRegions() {
+ return this.regions;
+ }
}
diff --git a/src/test/java/org/springframework/data/gemfire/support/AbstractNativeCacheTest.java b/src/test/java/org/springframework/data/gemfire/support/AbstractNativeCacheTest.java
deleted file mode 100644
index 637487cf..00000000
--- a/src/test/java/org/springframework/data/gemfire/support/AbstractNativeCacheTest.java
+++ /dev/null
@@ -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 {
-
- 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 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()));
- }
-
-}
diff --git a/src/test/java/org/springframework/data/gemfire/support/AbstractNativeCacheTests.java b/src/test/java/org/springframework/data/gemfire/support/AbstractNativeCacheTests.java
new file mode 100644
index 00000000..fe173605
--- /dev/null
+++ b/src/test/java/org/springframework/data/gemfire/support/AbstractNativeCacheTests.java
@@ -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 {
+
+ 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 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");
+ }
+}
diff --git a/src/test/java/org/springframework/data/gemfire/support/GemfireCacheTest.java b/src/test/java/org/springframework/data/gemfire/support/GemfireCacheIntegrationTests.java
similarity index 55%
rename from src/test/java/org/springframework/data/gemfire/support/GemfireCacheTest.java
rename to src/test/java/org/springframework/data/gemfire/support/GemfireCacheIntegrationTests.java
index a5ff0f14..3f0251d4 100644
--- a/src/test/java/org/springframework/data/gemfire/support/GemfireCacheTest.java
+++ b/src/test/java/org/springframework/data/gemfire/support/GemfireCacheIntegrationTests.java
@@ -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> {
+public class GemfireCacheIntegrationTests extends AbstractNativeCacheTests> {
@Rule
- public ExpectedException expectedException = ExpectedException.none();
+ public ExpectedException exception = ExpectedException.none();
@Override
- protected Cache createCache(Region