diff --git a/build.gradle b/build.gradle
index 8ab14bbc..668284c5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -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
diff --git a/gradle.properties b/gradle.properties
index 3835875f..df131faf 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -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
diff --git a/pom.xml b/pom.xml
index e0f9f709..e439d205 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
org.springframework.data.buildspring-data-parent
- 1.8.3.RELEASE
+ 1.9.0.BUILD-SNAPSHOTorg.springframework.data
@@ -20,7 +20,7 @@
SGF2.7.7
- 3.5.2
+ 2.5.01.0.0-incubating.M32.0.21.01
@@ -169,16 +169,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
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