From 14754be03e10ae8f48d6cc64aebe6d1f276c4b57 Mon Sep 17 00:00:00 2001 From: John Blum Date: Fri, 2 May 2014 14:46:42 -0700 Subject: [PATCH] Implements SGF-274 removing the use of temporary callback objects passed to the 'templated' execute method for each operation implementation in order to reduce the memory footprint, especially in the context of Repositories. --- .../data/gemfire/GemfireAccessor.java | 49 +- .../data/gemfire/GemfireCallback.java | 20 +- .../data/gemfire/GemfireOperations.java | 96 ++-- .../data/gemfire/GemfireTemplate.java | 466 ++++++++++-------- .../GemfireTemplateIntegrationTest.java | 336 +++++++++++++ .../data/gemfire/GemfireTemplateTest.java | 167 ++++++- ...GemfireTemplateIntegrationTest-context.xml | 25 + .../data/gemfire/basic-template.xml | 26 +- 8 files changed, 881 insertions(+), 304 deletions(-) create mode 100644 src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTest.java create mode 100644 src/test/resources/org/springframework/data/gemfire/GemfireTemplateIntegrationTest-context.xml diff --git a/src/main/java/org/springframework/data/gemfire/GemfireAccessor.java b/src/main/java/org/springframework/data/gemfire/GemfireAccessor.java index 5a96fa7a..ebe273cd 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireAccessor.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireAccessor.java @@ -20,6 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; +import org.springframework.util.Assert; import com.gemstone.gemfire.GemFireCheckedException; import com.gemstone.gemfire.GemFireException; @@ -31,18 +32,39 @@ import com.gemstone.gemfire.cache.Region; * Not intended to be used directly. * * @author Costin Leau + * @author John Blum + * @see org.springframework.beans.factory.InitializingBean + * @see com.gemstone.gemfire.cache.Region */ public class GemfireAccessor implements InitializingBean { - /** Logger available to subclasses */ protected final Log log = LogFactory.getLog(getClass()); - private Region region; + private Region region; + + /** + * Returns the template GemFire Cache Region. + * + * @return the GemFire Cache Region. + * @see com.gemstone.gemfire.cache.Region + */ + @SuppressWarnings("unchecked") + public Region getRegion() { + return region; + } + + /** + * Sets the template GemFire Cache Region. + * + * @param region the GemFire Cache Region used by this template. + * @see com.gemstone.gemfire.cache.Region + */ + public void setRegion(Region region) { + this.region = region; + } public void afterPropertiesSet() { - if (getRegion() == null) { - throw new IllegalArgumentException("Property 'region' is required"); - } + Assert.notNull(getRegion(), "The GemFire Cache Region is required."); } /** @@ -80,21 +102,4 @@ public class GemfireAccessor implements InitializingBean { return GemfireCacheUtils.convertQueryExceptions(ex); } - /** - * Returns the template region. - * - * @return the region - */ - public Region getRegion() { - return region; - } - - /** - * Sets the template region. - * - * @param region the region to set - */ - public void setRegion(Region region) { - this.region = region; - } } diff --git a/src/main/java/org/springframework/data/gemfire/GemfireCallback.java b/src/main/java/org/springframework/data/gemfire/GemfireCallback.java index 6e61ad94..858bd272 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireCallback.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireCallback.java @@ -26,19 +26,25 @@ import com.gemstone.gemfire.cache.Region; * operations on stored objects. * * @author Costin Leau + * @author John Blum + * @see com.gemstone.gemfire.cache.Region */ public interface GemfireCallback { /** - * Gets called by {@link GemfireTemplate#execute(GemfireCallback)}. Does not need to care about handling transactions - * or exceptions. + * Gets called by {@link GemfireTemplate#execute(GemfireCallback)}. Does not need to care about + * handling transactions or exceptions. * - * Allows for returning a result object created within the callback, i.e. a domain object or a collection of domain - * objects. A thrown custom RuntimeException is treated as an application exception: It gets propagated to the caller - * of the template. + * Allows a result object created within the callback to be returned, i.e. a domain object + * or a collection of domain objects. + * + * A thrown custom RuntimeException is treated as an application exception: it gets propagated to + * the caller of the template. * - * @param region GemFire Region - * @return a result object, or null if none + * @param region a GemFire Cache Region. + * @return a result object, or null if no result. + * @see com.gemstone.gemfire.cache.Region */ T doInGemfire(Region region) throws GemFireCheckedException, GemFireException; + } diff --git a/src/main/java/org/springframework/data/gemfire/GemfireOperations.java b/src/main/java/org/springframework/data/gemfire/GemfireOperations.java index e41af2dd..ac32108b 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireOperations.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireOperations.java @@ -25,97 +25,103 @@ import com.gemstone.gemfire.cache.query.SelectResults; /** * @author David Turanski - * + * @author John Blum */ public interface GemfireOperations { - public abstract boolean containsKey(Object key); + boolean containsKey(Object key); - public abstract boolean containsKeyOnServer(Object key); + boolean containsKeyOnServer(Object key); - public abstract boolean containsValue(Object value); + boolean containsValue(Object value); - public abstract boolean containsValueForKey(Object key); + boolean containsValueForKey(Object key); - public abstract void create(K key, V value); + void create(K key, V value); - public abstract V get(K key); + V get(K key); - public abstract V put(K key, V value); + Map getAll(Collection keys); - public abstract V putIfAbsent(K key, V value); + V put(K key, V value); - public abstract V remove(K key); + void putAll(Map map); - public abstract V replace(K key, V value); + V putIfAbsent(K key, V value); - public abstract boolean replace(K key, V oldValue, V newValue); + V replace(K key, V value); - public abstract Map getAll(Collection keys); + boolean replace(K key, V oldValue, V newValue); - public abstract void putAll(Map map); - - /** - * Shortcut for {@link Region#query(String)} method. Filters the values of this region using the predicate given as a string with the syntax of the WHERE clause of the query language. - * The predefined variable this may be used inside the predicate to denote the current element being filtered. - * This method evaluates the passed in where clause and returns results. It is supported on servers as well as clients. - * When executed on a client, this method always runs on the server and returns results. - * When invoking this method from the client, applications can pass in a where clause or a complete query. - - * @see Region#query(String) - * @param query A query language boolean query predicate. - * @return A SelectResults containing the values of this Region that match the predicate. - */ - public abstract SelectResults query(String query); + V remove(K key); /** * Executes a GemFire query with the given (optional) parameters and returns the result. Note this method expects the query to return multiple results; for queries that return only one * element use {@link #findUnique(String, Object...)}. * * As oppose, to the {@link #query(String)} method, this method allows for more generic queries (against multiple regions even) to be executed. - * + * * Note that the local query service is used if the region is configured as a client without any pool configuration or server connectivity - otherwise the query service on the default pool * is being used. - * + * * @see QueryService#newQuery(String) * @see Query#execute(Object[]) * @see SelectResults * @param query GemFire query - * @param params Values that are bound to parameters (such as $1) in this query. + * @param params Values that are bound to parameters (such as $1) in this query. * @return A {@link SelectResults} instance holding the objects matching the query * @throws InvalidDataAccessApiUsageException in case the query returns a single result (not a {@link SelectResults}). */ - public abstract SelectResults find(String query, Object... params) throws InvalidDataAccessApiUsageException; + SelectResults find(String query, Object... params) throws InvalidDataAccessApiUsageException; /** * Executes a GemFire query with the given (optional) parameters and returns the result. Note this method expects the query to return a single result; for queries that return multiple * elements use {@link #find(String, Object...)}. * * As oppose, to the {@link #query(String)} method, this method allows for more generic queries (against multiple regions even) to be executed. - * + * * Note that the local query service is used if the region is configured as a client without any pool configuration or server connectivity - otherwise the query service on the default pool * is being used. - * + * * @see QueryService#newQuery(String) * @see Query#execute(Object[]) * @param query GemFire query * @param params Values that are bound to parameters (such as $1) in this query. * @return The (single) object that represents the result of the query. - * @throws InvalidDataAccessApiUsageException in case the query returns multiple objects (through {@link SelectResults}). + * @throws InvalidDataAccessApiUsageException in case the query returns multiple objects (through {@link SelectResults}). */ - public abstract T findUnique(String query, Object... params) throws InvalidDataAccessApiUsageException; - - public abstract T execute(GemfireCallback action) throws DataAccessException; + T findUnique(String query, Object... params) throws InvalidDataAccessApiUsageException; /** - * Execute the action specified by the given action object within a - * Region. - * @param action callback object that specifies the Gemfire action - * @param exposeNativeRegion whether to expose the native - * GemFire region to callback code - * @return a result object returned by the action, or null - * @throws org.springframework.dao.DataAccessException in case of GemFire errors + * Shortcut for {@link Region#query(String)} method. Filters the values of this region using the predicate given as a string with the syntax of the WHERE clause of the query language. + * The predefined variable this may be used inside the predicate to denote the current element being filtered. + * This method evaluates the passed in where clause and returns results. It is supported on servers as well as clients. + * When executed on a client, this method always runs on the server and returns results. + * When invoking this method from the client, applications can pass in a where clause or a complete query. + + * @see Region#query(String) + * @param query A query language boolean query predicate. + * @return A SelectResults containing the values of this Region that match the predicate. */ - public abstract T execute(GemfireCallback action, boolean exposeNativeRegion) throws DataAccessException; + SelectResults query(String query); + + /** + * Execute the action specified by the given action object within a Region. + * + * @param action callback object that specifies the Gemfire action to execute. + * @return a result object returned by the action, or null. + * @throws org.springframework.dao.DataAccessException in case of GemFire errors. + */ + T execute(GemfireCallback action) throws DataAccessException; + + /** + * Execute the action specified by the given action object within a Region. + * + * @param action callback object that specifies the Gemfire action to execute. + * @param exposeNativeRegion whether to expose the native GemFire region to callback code. + * @return a result object returned by the action, or null. + * @throws org.springframework.dao.DataAccessException in case of GemFire errors. + */ + T execute(GemfireCallback action, boolean exposeNativeRegion) throws DataAccessException; } diff --git a/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java b/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java index ed0c8bda..c7491f59 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java @@ -44,7 +44,6 @@ import com.gemstone.gemfire.internal.cache.LocalRegion; * Helper class that simplifies GemFire data access code and converts {@link GemFireCheckedException} and * {@link GemFireException} into Spring {@link DataAccessException}, following the org.springframework.dao * exception hierarchy. - * * * The central method is execute, supporting GemFire access code implementing the GemfireCallback interface. * It provides dedicated handling such that neither the GemfireCallback implementation nor the calling code needs to @@ -52,9 +51,18 @@ import com.gemstone.gemfire.internal.cache.LocalRegion; * Typically used to implement data access or business logic services that use GemFire within their implementation but * are GemFire-agnostic in their interface. The latter or code calling the latter only have to deal with business * objects, query objects, and org.springframework.dao exceptions. - * + * * @author Costin Leau + * @author John Blum + * @see java.util.Map + * @see org.springframework.data.gemfire.GemfireAccessor + * @see org.springframework.data.gemfire.GemfireOperations + * @see com.gemstone.gemfire.cache.Region + * @see com.gemstone.gemfire.cache.query.Query + * @see com.gemstone.gemfire.cache.query.QueryService + * @see com.gemstone.gemfire.cache.query.SelectResults */ +@SuppressWarnings("unused") public class GemfireTemplate extends GemfireAccessor implements GemfireOperations { private boolean exposeNativeRegion = false; @@ -101,11 +109,7 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public boolean containsKey(final Object key) { - return execute(new GemfireCallback() { - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return region.containsKey(key); - } - }); + return getRegion().containsKey(key); } /* (non-Javadoc) @@ -113,11 +117,7 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public boolean containsKeyOnServer(final Object key) { - return execute(new GemfireCallback() { - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return region.containsKeyOnServer(key); - } - }); + return getRegion().containsKeyOnServer(key); } /* (non-Javadoc) @@ -125,11 +125,7 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public boolean containsValue(final Object value) { - return execute(new GemfireCallback() { - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return region.containsValue(value); - } - }); + return getRegion().containsValue(value); } /* (non-Javadoc) @@ -137,11 +133,7 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public boolean containsValueForKey(final Object key) { - return execute(new GemfireCallback() { - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return region.containsValueForKey(key); - } - }); + return getRegion().containsValueForKey(key); } /* (non-Javadoc) @@ -149,13 +141,12 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public void create(final K key, final V value) { - execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Object doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - region.create(key, value); - return null; - } - }); + try { + getRegion().create(key, value); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } } /* (non-Javadoc) @@ -163,77 +154,12 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public V get(final K key) { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return (V) region.get(key); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.GemfireOperations#put(K, V) - */ - @Override - public V put(final K key, final V value) { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return (V) region.put(key, value); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.GemfireOperations#putIfAbsent(K, V) - */ - @Override - public V putIfAbsent(final K key, final V value) { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return (V) region.putIfAbsent(key, value); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.GemfireOperations#remove(K) - */ - @Override - public V remove(final K key) { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return (V) region.remove(key); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.GemfireOperations#replace(K, V) - */ - @Override - public V replace(final K key, final V value) { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return (V) region.replace(key, value); - } - }); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.GemfireOperations#replace(K, V, V) - */ - @Override - public boolean replace(final K key, final V oldValue, final V newValue) { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return region.replace(key, oldValue, newValue); - } - }); + try { + return this.getRegion().get(key); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } } /* (non-Javadoc) @@ -241,12 +167,25 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public Map getAll(final Collection keys) { - return execute(new GemfireCallback>() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Map doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return (Map) region.getAll(keys); - } - }); + try { + return this.getRegion().getAll(keys); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#put(K, V) + */ + @Override + public V put(final K key, final V value) { + try { + return this.getRegion().put(key, value); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } } /* (non-Javadoc) @@ -254,13 +193,64 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public void putAll(final Map map) { - execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Object doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - region.putAll(map); - return null; - } - }); + try { + this.getRegion().putAll(map); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#putIfAbsent(K, V) + */ + @Override + public V putIfAbsent(final K key, final V value) { + try { + return this.getRegion().putIfAbsent(key, value); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#remove(K) + */ + @Override + public V remove(final K key) { + try { + return this.getRegion().remove(key); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#replace(K, V) + */ + @Override + public V replace(final K key, final V value) { + try { + return this.getRegion().replace(key, value); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#replace(K, V, V) + */ + @Override + public boolean replace(final K key, final V oldValue, final V newValue) { + try { + return this.getRegion().replace(key, oldValue, newValue); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } } /* (non-Javadoc) @@ -268,78 +258,164 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation */ @Override public SelectResults query(final String query) { - return execute(new GemfireCallback>() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public SelectResults doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - return region.query(query); + try { + return this.getRegion().query(query); + } + catch (IndexInvalidException ex) { + throw convertGemFireQueryException(ex); + } + catch (QueryInvalidException ex) { + throw convertGemFireQueryException(ex); + } + catch (GemFireCheckedException e) { + throw convertGemFireAccessException(e); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + catch (RuntimeException ex) { + // test for CqInvalidException (removed in 6.5) + if (GemfireCacheUtils.isCqInvalidException(ex)) { + throw GemfireCacheUtils.convertCqInvalidException(ex); } - }); + + // callback code threw application exception + throw ex; + } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#find(java.lang.String, java.lang.Object) */ @Override - public SelectResults find(final String query, final Object... params) - throws InvalidDataAccessApiUsageException { - return execute(new GemfireCallback>() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public SelectResults doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - QueryService queryService = lookupQueryService(region); - Query q = queryService.newQuery(query); - Object result = q.execute(params); - if (result instanceof SelectResults) { - return (SelectResults) result; - } - throw new InvalidDataAccessApiUsageException( - "Result object returned from GemfireCallback isn't a SelectResult: [" + result + "]"); + @SuppressWarnings("unchecked") + public SelectResults find(final String queryString, final Object... params) throws InvalidDataAccessApiUsageException { + try { + QueryService queryService = lookupQueryService(getRegion()); + Query query = queryService.newQuery(queryString); + Object result = query.execute(params); + + if (result instanceof SelectResults) { + return (SelectResults) result; } - }); + else { + throw new InvalidDataAccessApiUsageException( + "Result object returned from GemfireCallback isn't a SelectResult: [" + result + "]"); + } + } + catch (IndexInvalidException ex) { + throw convertGemFireQueryException(ex); + } + catch (QueryInvalidException ex) { + throw convertGemFireQueryException(ex); + } + catch (GemFireCheckedException e) { + throw convertGemFireAccessException(e); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + catch (RuntimeException ex) { + // test for CqInvalidException (removed in 6.5) + if (GemfireCacheUtils.isCqInvalidException(ex)) { + throw GemfireCacheUtils.convertCqInvalidException(ex); + } + + // callback code threw application exception + throw ex; + } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#findUnique(java.lang.String, java.lang.Object) */ @Override - public T findUnique(final String query, final Object... params) throws InvalidDataAccessApiUsageException { - return execute(new GemfireCallback() { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public T doInGemfire(Region region) throws GemFireCheckedException, GemFireException { - QueryService queryService = lookupQueryService(region); - Query q = queryService.newQuery(query); - Object result = q.execute(params); - if (result instanceof SelectResults) { - SelectResults selectResults = (SelectResults)result; - if (selectResults.asList().size() == 1) { - result = selectResults.iterator().next(); - } else { - throw new InvalidDataAccessApiUsageException( - "Result object returned from GemfireCallback isn't unique: [" + result + "]"); - } - } - return (T) result; - } - }); - } + @SuppressWarnings("unchecked") + public T findUnique(final String queryString, final Object... params) throws InvalidDataAccessApiUsageException { + try { + QueryService queryService = lookupQueryService(getRegion()); + Query query = queryService.newQuery(queryString); + Object result = query.execute(params); + if (result instanceof SelectResults) { + SelectResults selectResults = (SelectResults) result; + + if (selectResults.asList().size() == 1) { + result = selectResults.iterator().next(); + } + else { + throw new InvalidDataAccessApiUsageException(String.format( + "The result returned from query (%1$s) is not unique: (%2$s).", queryString, result)); + } + } + + return (T) result; + } + catch (IndexInvalidException ex) { + throw convertGemFireQueryException(ex); + } + catch (QueryInvalidException ex) { + throw convertGemFireQueryException(ex); + } + catch (GemFireCheckedException e) { + throw convertGemFireAccessException(e); + } + catch (GemFireException e) { + throw convertGemFireAccessException(e); + } + catch (RuntimeException ex) { + // test for CqInvalidException (removed in 6.5) + if (GemfireCacheUtils.isCqInvalidException(ex)) { + throw GemfireCacheUtils.convertCqInvalidException(ex); + } + + // callback code threw application exception + throw ex; + } + } /** * Returns the query service used by the template in its find methods. * * @param region region to find the local query service from * @return query service to use, local or generic + * @see com.gemstone.gemfire.cache.Region + * @see com.gemstone.gemfire.cache.Region#getRegionService() + * @see com.gemstone.gemfire.cache.RegionService#getQueryService() + * @see com.gemstone.gemfire.cache.client.ClientCache#getLocalQueryService() */ - protected QueryService lookupQueryService(Region region) { - if (region.getRegionService() instanceof ClientCache - && (region instanceof LocalRegion && !((LocalRegion) region).hasServerProxy()) - && Scope.LOCAL.equals(region.getAttributes().getScope())) { - return ((ClientCache) region.getRegionService()).getLocalQueryService(); - } - return region.getRegionService().getQueryService(); + protected QueryService lookupQueryService(final Region region) { + return (requiresLocalQueryService(region) ? ((ClientCache) region.getRegionService()).getLocalQueryService() + : region.getRegionService().getQueryService()); } + /* + * (non-Javadoc) + * @see com.gemstone.gemfire.cache.Region + * @see com.gemstone.gemfire.internal.cache.LocalRegion + */ + /* package-private */ boolean isLocalWithNoServerProxy(final Region region) { + return (region instanceof LocalRegion && !((LocalRegion) region).hasServerProxy()); + } - /* (non-Javadoc) + /* + * (non-Javadoc) + * @see #isLocalWithNoServerProxy(:Region) + * @see com.gemstone.gemfire.cache.Region + * @see com.gemstone.gemfire.cache.RegionAttributes + * @see com.gemstone.gemfire.cache.RegionAttributes#getScope() + * @see com.gemstone.gemfire.cache.Scope + * @see com.gemstone.gemfire.cache.client.ClientCache + * @see com.gemstone.gemfire.internal.cache.LocalRegion + * @see com.gemstone.gemfire.internal.cache.LocalRegion#hasServerProxy() + */ + private boolean requiresLocalQueryService(final Region region) { + return (region.getRegionService() instanceof ClientCache && isLocalWithNoServerProxy(region) + && Scope.LOCAL.equals(region.getAttributes().getScope())); + } + + /* + * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#execute(org.springframework.data.gemfire.GemfireCallback) */ @Override @@ -347,7 +423,8 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation return execute(action, isExposeNativeRegion()); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#execute(org.springframework.data.gemfire.GemfireCallback, boolean) */ @Override @@ -355,21 +432,26 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation Assert.notNull(action, "Callback object must not be null"); try { Region regionToExpose = (exposeNativeRegion ? getRegion() : regionProxy); - T result = action.doInGemfire(regionToExpose); - return result; - } catch (IndexInvalidException ex) { + return action.doInGemfire(regionToExpose); + } + catch (IndexInvalidException ex) { throw convertGemFireQueryException(ex); - } catch (QueryInvalidException ex) { + } + catch (QueryInvalidException ex) { throw convertGemFireQueryException(ex); - } catch (GemFireCheckedException ex) { + } + catch (GemFireCheckedException ex) { throw convertGemFireAccessException(ex); - } catch (GemFireException ex) { + } + catch (GemFireException ex) { throw convertGemFireAccessException(ex); - } catch (RuntimeException ex) { - // try first the CqInvalidException (removed in 6.5) + } + catch (RuntimeException ex) { + // test for CqInvalidException (removed in 6.5) if (GemfireCacheUtils.isCqInvalidException(ex)) { throw GemfireCacheUtils.convertCqInvalidException(ex); } + // callback code threw application exception throw ex; } @@ -386,51 +468,49 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation * @see #execute(GemfireCallback, boolean) */ @SuppressWarnings("unchecked") - protected Region createRegionProxy(Region region) { - Class[] ifcs = ClassUtils.getAllInterfacesForClass(region.getClass(), getClass().getClassLoader()); - return (Region) Proxy.newProxyInstance(region.getClass().getClassLoader(), ifcs, - new CloseSuppressingInvocationHandler(region)); + protected Region createRegionProxy(final Region region) { + return (Region) Proxy.newProxyInstance(region.getClass().getClassLoader(), + ClassUtils.getAllInterfacesForClass(region.getClass(), getClass().getClassLoader()), + new RegionCloseSuppressingInvocationHandler(region)); } - //------------------------------------------------------------------------- - // Convenience methods for load, save, delete - //------------------------------------------------------------------------- - /** - * Invocation handler that suppresses close calls on GemFire Regions. - * @see Region#close() + * InvocationHandler that suppresses close calls on GemFire Cache Regions. + * + * @see com.gemstone.gemfire.cache.Region#close() + * @see java.lang.reflect.InvocationHandler */ - private static class CloseSuppressingInvocationHandler implements InvocationHandler { + private static class RegionCloseSuppressingInvocationHandler implements InvocationHandler { private final Region target; - public CloseSuppressingInvocationHandler(Region target) { + public RegionCloseSuppressingInvocationHandler(final Region target) { + Assert.notNull(target, "The Region to target must not be null."); this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // Invocation on Region interface coming in... - if (method.getName().equals("equals")) { - // Only consider equal when proxies are identical. + // only consider equal when proxies are identical return (proxy == args[0]); } else if (method.getName().equals("hashCode")) { - // Use hashCode of region proxy. + // use hashCode of Region proxy return System.identityHashCode(proxy); } else if (method.getName().equals("close")) { - // Handle close method: suppress, not valid. + // suppress Region.close() method call return null; } - - // Invoke method on target Region - try { - Object retVal = method.invoke(this.target, args); - return retVal; - } catch (InvocationTargetException ex) { - throw ex.getTargetException(); + else { + try { + return method.invoke(this.target, args); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } } } } + } diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTest.java new file mode 100644 index 00000000..585ddd58 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateIntegrationTest.java @@ -0,0 +1,336 @@ +/* + * Copyright 2010-2013 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Resource; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.gemfire.repository.sample.User; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.query.SelectResults; + +/** + * The GemfireTemplateIntegrationTest class is a test suite of test cases testing the contract and functionality + * of the SDG GemfireTemplate class for wrapping a GemFire Cache Region and performing Cache Region operations. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @since 1.4.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +@SuppressWarnings("unused") +public class GemfireTemplateIntegrationTest { + + protected static final List TEST_USER_LIST = new ArrayList(11); + + static { + TEST_USER_LIST.add(createUser("jonDoe")); + TEST_USER_LIST.add(createUser("janeDoe", false)); + TEST_USER_LIST.add(createUser("pieDoe", false)); + TEST_USER_LIST.add(createUser("cookieDoe")); + TEST_USER_LIST.add(createUser("jackHandy")); + TEST_USER_LIST.add(createUser("mandyHandy", false)); + TEST_USER_LIST.add(createUser("randyHandy", false)); + TEST_USER_LIST.add(createUser("sandyHandy")); + TEST_USER_LIST.add(createUser("imaPigg")); + } + + @Resource(name = "Users") + private Region users; + + @Autowired + private GemfireTemplate usersTemplate; + + protected static User createUser(final String username) { + return createUser(username, true); + } + + protected static User createUser(final String username, final Boolean active) { + return createUser(username, String.format("%1$s@companyx.com", username), Calendar.getInstance(), active); + } + + protected static User createUser(final String username, final String email, final Calendar since, final Boolean active) { + User user = new User(username); + user.setActive(Boolean.TRUE.equals(active)); + user.setEmail(email); + user.setSince(since); + return user; + } + + protected String getKey(final User user) { + return (user != null ? user.getUsername() : null); + } + + protected User getUser(final String username) { + for (User user : TEST_USER_LIST) { + if (user.getUsername().equals(username)) { + return user; + } + } + + return null; + } + + protected List getUsers(final String... usernames) { + List users = new ArrayList(usernames.length); + List usernameList = Arrays.asList(usernames); + + for (User user : TEST_USER_LIST) { + if (usernameList.contains(user.getUsername())) { + users.add(user); + } + } + + return users; + } + + protected Map getUsersAsMap(final User... users) { + Map userMap = new HashMap(users.length); + + for (User user : users) { + userMap.put(getKey(user), user); + } + + return userMap; + } + + protected void assertNullEquals(final Object value1, final Object value2) { + Assert.assertTrue(value1 == null ? value2 == null : value1.equals(value2)); + } + + @Before + public void setup() { + assertNotNull("The 'Users' Region was not properly configured and initialized!", users); + + if (users.isEmpty()) { + for (User user : TEST_USER_LIST) { + users.put(getKey(user), user); + } + + assertFalse(users.isEmpty()); + assertEquals(TEST_USER_LIST.size(), users.size()); + } + } + + @Test + public void testContainsKey() { + assertTrue(usersTemplate.containsKey(getKey(getUser("jonDoe")))); + assertFalse(usersTemplate.containsKey("dukeNukem")); + } + + @Test + @Ignore + public void testContainsKeyOnServer() { + assertTrue(usersTemplate.containsKeyOnServer(getKey(getUser("jackHandy")))); + assertFalse(usersTemplate.containsKeyOnServer("maxPayne")); + } + + @Test + public void testContainsValue() { + assertTrue(usersTemplate.containsValue(getUser("pieDoe"))); + assertFalse(usersTemplate.containsValue(createUser("pieDough"))); + } + + @Test + public void testContainsValueForKey() { + assertTrue(usersTemplate.containsValueForKey(getKey(getUser("cookieDoe")))); + assertFalse(usersTemplate.containsValueForKey("chocolateChipCookieDoe")); + } + + @Test + public void testCreate() { + User bartSimpson = createUser("bartSimpson"); + + usersTemplate.create(getKey(bartSimpson), bartSimpson); + + assertTrue(users.containsKey(getKey(bartSimpson))); + assertTrue(users.containsValueForKey(getKey(bartSimpson))); + assertTrue(users.containsValue(bartSimpson)); + assertEquals(bartSimpson, users.get(getKey(bartSimpson))); + } + + @Test + public void testGet() { + assertEquals(users.get(getKey(getUser("imaPigg"))), usersTemplate.get(getKey(getUser("imaPigg")))); + assertNullEquals(users.get("mrT"), usersTemplate.get("mrT")); + } + + @Test + public void testPut() { + User peterGriffon = createUser("peterGriffon"); + + assertNull(usersTemplate.put(getKey(peterGriffon), peterGriffon)); + assertEquals(peterGriffon, users.get(getKey(peterGriffon))); + } + + @Test + public void testPutIfAbsent() { + User stewieGriffon = createUser("stewieGriffon"); + + assertFalse(users.containsValue(stewieGriffon)); + assertNull(usersTemplate.putIfAbsent(getKey(stewieGriffon), stewieGriffon)); + assertTrue(users.containsValue(stewieGriffon)); + assertEquals(stewieGriffon, usersTemplate.putIfAbsent(getKey(stewieGriffon), createUser("megGriffon"))); + assertEquals(stewieGriffon, users.get(getKey(stewieGriffon))); + } + + @Test + public void testRemove() { + User mandyHandy = users.get(getKey(getUser("mandyHandy"))); + + assertNotNull(mandyHandy); + assertEquals(mandyHandy, usersTemplate.remove(getKey(mandyHandy))); + assertFalse(users.containsKey(getKey(mandyHandy))); + assertFalse(users.containsValue(mandyHandy)); + assertFalse(users.containsKey("loisGriffon")); + assertNull(usersTemplate.remove("loisGriffon")); + assertFalse(users.containsKey("loisGriffon")); + } + + @Test + public void testReplace() { + User randyHandy = users.get(getKey(getUser("randyHandy"))); + User lukeFluke = createUser("lukeFluke"); + User chrisGriffon = createUser("chrisGriffon"); + + assertNotNull(randyHandy); + assertEquals(randyHandy, usersTemplate.replace(getKey(randyHandy), lukeFluke)); + assertEquals(lukeFluke, users.get(getKey(randyHandy))); + assertFalse(users.containsValue(randyHandy)); + assertFalse(users.containsValue(chrisGriffon)); + assertNull(usersTemplate.replace(getKey(chrisGriffon), chrisGriffon)); + assertFalse(users.containsValue(chrisGriffon)); + } + + @Test + public void testReplaceOldValueWithNewValue() { + User jackHandy = getUser("jackHandy"); + User imaPigg = getUser("imaPigg"); + + assertTrue(users.containsValue(jackHandy)); + assertFalse(usersTemplate.replace(getKey(jackHandy), null, imaPigg)); + assertTrue(users.containsValue(jackHandy)); + assertEquals(jackHandy, users.get(getKey(jackHandy))); + assertTrue(usersTemplate.replace(getKey(jackHandy), jackHandy, imaPigg)); + assertFalse(users.containsValue(jackHandy)); + assertEquals(imaPigg, users.get(getKey(jackHandy))); + } + + @Test + public void testGetAllReturnsNoResults() { + List keys = Arrays.asList("keyOne", "keyTwo", "keyThree"); + + Map actualUserMapping = usersTemplate.getAll(keys); + Map expectedUserMapping = users.getAll(keys); + + assertEquals(expectedUserMapping, actualUserMapping); + } + + @Test + public void testGetAllReturnsResults() { + List keys = Arrays.asList(getKey(getUser("jonDoe")), getKey(getUser("pieDoe"))); + + Map actualUserMapping = usersTemplate.getAll(keys); + Map expectedUserMapping = users.getAll(keys); + + assertEquals(actualUserMapping, expectedUserMapping); + } + + @Test + public void testPutAll() { + User batMan = createUser("batMap"); + User spiderMan = createUser("spiderMan"); + User superMan = createUser("superMan"); + + Map userMap = getUsersAsMap(batMan, spiderMan, superMan); + + assertFalse(users.keySet().containsAll(userMap.keySet())); + assertFalse(users.values().containsAll(userMap.values())); + + usersTemplate.putAll(userMap); + + assertTrue(users.keySet().containsAll(userMap.keySet())); + assertTrue(users.values().containsAll(userMap.values())); + } + + @Test + public void testQuery() { + SelectResults queryResults = usersTemplate.query("username LIKE '%Doe'"); + + assertNotNull(queryResults); + + List queriedUsers = queryResults.asList(); + + assertNotNull(queriedUsers); + assertFalse(queriedUsers.isEmpty()); + assertEquals(4, queriedUsers.size()); + assertTrue(queriedUsers.containsAll(getUsers("jonDoe", "janeDoe", "pieDoe", "cookieDoe"))); + } + + @Test + public void testFind() { + SelectResults findResults = usersTemplate.find("SELECT u FROM /Users u WHERE u.username LIKE $1 AND u.active = $2", "%Doe", true); + + assertNotNull(findResults); + + List usersFound = findResults.asList(); + + assertNotNull(usersFound); + assertFalse(usersFound.isEmpty()); + assertEquals(2, usersFound.size()); + assertTrue(usersFound.containsAll(getUsers("jonDoe", "cookieDoe"))); + } + + @Test + public void testFindUniqueReturnsResult() { + User jonDoe = usersTemplate.findUnique("SELECT u FROM /Users u WHERE u.username = $1", "jonDoe"); + + assertNotNull(jonDoe); + assertEquals(getUser("jonDoe"), jonDoe); + } + + @Test(expected = InvalidDataAccessApiUsageException.class) + public void testFindUniqueReturnsNoResult() { + usersTemplate.findUnique("SELECT u FROM /Users u WHERE u.username = $1", "benDover"); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java index f03c99ee..9db23085 100644 --- a/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java @@ -17,11 +17,21 @@ package org.springframework.data.gemfire; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Resource; + +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +42,12 @@ import org.springframework.data.gemfire.test.MockRegionFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.gemstone.gemfire.GemFireCheckedException; +import com.gemstone.gemfire.GemFireException; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionAttributes; +import com.gemstone.gemfire.cache.Scope; +import com.gemstone.gemfire.cache.client.ClientCache; import com.gemstone.gemfire.cache.query.FunctionDomainException; import com.gemstone.gemfire.cache.query.NameResolutionException; import com.gemstone.gemfire.cache.query.Query; @@ -41,33 +57,109 @@ import com.gemstone.gemfire.cache.query.SelectResults; import com.gemstone.gemfire.cache.query.TypeMismatchException; /** + * The GemfireTemplateTest class is a test suite of test case testing the contract and functionality of the + * GemfirTemplate class. + * * @author Costin Leau + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer + * @see org.springframework.test.context.ContextConfiguration */ +@ContextConfiguration(locations="basic-template.xml", initializers=GemfireTestApplicationContextInitializer.class) @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations="/org/springframework/data/gemfire/basic-template.xml", -initializers=GemfireTestApplicationContextInitializer.class) +@SuppressWarnings("unused") public class GemfireTemplateTest { - private static final String MULTI_QUERY = "select * from /simple"; + private static final String MULTI_QUERY = "SELECT * FROM /simple"; + private static final String SINGLE_QUERY = "(SELECT * FROM /simple).size"; - private static final String SINGLE_QUERY = "(select * from /simple).size"; - - @Autowired GemfireOperations template; - + @Autowired + private GemfireTemplate template; + + @Resource(name = "simple") + private Region simple; + + @Before @SuppressWarnings("rawtypes") - @Before public void setUp() throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException { - //Only applies if Mocks are enabled - QueryService querySevice = MockRegionFactory.mockQueryService(); + QueryService queryService = MockRegionFactory.mockQueryService(); Query singleQuery = mock(Query.class); + when(singleQuery.execute(any(Object[].class))).thenReturn(0); + when(queryService.newQuery(SINGLE_QUERY)).thenReturn(singleQuery); + Query multipleQuery = mock(Query.class); - SelectResults selectResults = mock(SelectResults.class); + when(multipleQuery.execute(any(Object[].class))).thenReturn(selectResults); - - when(querySevice.newQuery(SINGLE_QUERY)).thenReturn(singleQuery); - when(querySevice.newQuery(MULTI_QUERY)).thenReturn(multipleQuery); + when(queryService.newQuery(MULTI_QUERY)).thenReturn(multipleQuery); + } + + @After + public void tearDown() { + template.setExposeNativeRegion(false); + } + + @Test + public void testConstructWithNonNullRegion() { + GemfireTemplate localTemplate = new GemfireTemplate(simple); + + assertNotNull(localTemplate); + assertSame(simple, localTemplate.getRegion()); + assertFalse(localTemplate.isExposeNativeRegion()); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructWithNullRegion() { + try { + new GemfireTemplate(null); + } + catch (IllegalArgumentException expected) { + assertEquals("The GemFire Cache Region is required.", expected.getMessage()); + throw expected; + } + } + + @Test + public void testExecuteUsingNativeRegion() { + template.setExposeNativeRegion(true); + + assertTrue(template.isExposeNativeRegion()); + assertSame(simple, template.getRegion()); + + final AtomicBoolean callbackInvoked = new AtomicBoolean(false); + + template.execute(new GemfireCallback() { + @Override + public Object doInGemfire(final Region region) throws GemFireCheckedException, GemFireException { + callbackInvoked.set(true); + assertSame(simple, region); + return null; + } + }); + + assertTrue(callbackInvoked.get()); + } + + @Test + public void testExecuteUsingProxyRegion() { + assertFalse(template.isExposeNativeRegion()); + + final AtomicBoolean callbackInvoked = new AtomicBoolean(false); + + template.execute(new GemfireCallback() { + @Override + public Object doInGemfire(final Region region) throws GemFireCheckedException, GemFireException { + callbackInvoked.set(true); + assertNotSame(simple, region); + return null; + } + }); + + assertTrue(callbackInvoked.get()); } @Test(expected = InvalidDataAccessApiUsageException.class) @@ -82,14 +174,43 @@ public class GemfireTemplateTest { @Test public void testFind() throws Exception { - SelectResults find = template.find(MULTI_QUERY); - assertNotNull(find); - } - - @Test - public void testFindUnique() throws Exception { - Integer find = template.findUnique(SINGLE_QUERY); - assertEquals(find, Integer.valueOf(0)); + assertNotNull(template.find(MULTI_QUERY)); } -} \ No newline at end of file + @Test + public void testFindUnique() throws Exception { + assertEquals(0, template.findUnique(SINGLE_QUERY)); + } + + @Test + public void testLookupQueryService() { + assertSame(simple.getRegionService().getQueryService(), template.lookupQueryService(simple)); + } + + @Test + @SuppressWarnings("unchecked") + public void testLookupLocalQueryService() { + ClientCache mockClientCache = mock(ClientCache.class, "testLookupLocalQueryService.ClientCache"); + Region mockRegion = mock(Region.class, "testLookupLocalQueryService.Region"); + QueryService mockQueryService = mock(QueryService.class, "testLookupLocalQueryService.QueryService"); + RegionAttributes mockRegionAttributes = mock(RegionAttributes.class, "testLookupLocalQueryService.RegionAttributes"); + + when(mockClientCache.getLocalQueryService()).thenReturn(mockQueryService); + when(mockRegion.getRegionService()).thenReturn(mockClientCache); + when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes); + when(mockRegionAttributes.getScope()).thenReturn(Scope.LOCAL); + + GemfireTemplate localTemplate = new GemfireTemplate(mockRegion) { + @Override boolean isLocalWithNoServerProxy(final Region region) { + return true; + } + }; + + assertSame(mockQueryService, localTemplate.lookupQueryService(mockRegion)); + + verify(mockClientCache, times(1)).getLocalQueryService(); + verify(mockRegion, times(2)).getRegionService(); + verify(mockRegionAttributes, times(1)).getScope(); + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/GemfireTemplateIntegrationTest-context.xml b/src/test/resources/org/springframework/data/gemfire/GemfireTemplateIntegrationTest-context.xml new file mode 100644 index 00000000..2866f7ca --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/GemfireTemplateIntegrationTest-context.xml @@ -0,0 +1,25 @@ + + + + + GemfireTemplateIntegrationTest + 0 + config + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/basic-template.xml b/src/test/resources/org/springframework/data/gemfire/basic-template.xml index f1459094..695b1796 100644 --- a/src/test/resources/org/springframework/data/gemfire/basic-template.xml +++ b/src/test/resources/org/springframework/data/gemfire/basic-template.xml @@ -1,18 +1,16 @@ + xmlns:gfe="http://www.springframework.org/schema/gemfire" + xmlns:p="http://www.springframework.org/schema/p" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +"> + + + + + + - - - - - - - -