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 +"> + + + + + + - - - - - - - -