diff --git a/docs/src/info/changelog.txt b/docs/src/info/changelog.txt index e732d5b9..6e94b83a 100644 --- a/docs/src/info/changelog.txt +++ b/docs/src/info/changelog.txt @@ -1,11 +1,12 @@ SPRING DATA GEMFIRE CHANGELOG ============================= http://www.springsource.org/spring-gemfire -Changes in version 1.3.0.RELEASE (2013-02-15) +Changes in version 1.3.0.RELEASE (2013-03-14) +--------------------------------------------- General * Added annotation support for GemFire functions * Added 'datasource' element to gfe-data namespace to simplify client connection - +* Added support for JSON See [release notes](https://jira.springsource.org/secure/ReleaseNote.jspa?projectId=10462&version=13300) Changes in version 1.2.1.RELEASE (2012-10-26) diff --git a/docs/src/reference/docbook/introduction/new-features.xml b/docs/src/reference/docbook/introduction/new-features.xml index 19e9bf42..45a01980 100644 --- a/docs/src/reference/docbook/introduction/new-features.xml +++ b/docs/src/reference/docbook/introduction/new-features.xml @@ -17,7 +17,7 @@
- New in the 1.3.0.Release + New in the 1.3.0 Release @@ -29,9 +29,25 @@ - A <datasource> tag has been added to the + We have added a <datasource> tag to the gfe-data XML namespace. This simplifies - establishing a basic client connection to a GemFire data grid. + establishing a basic client connection to a GemFire data + grid. + + + + To support JSON features introduced in GemFire 7.0, we have + added a ,<json-region-autoproxy> tag to the gfe-data XML + namespace, enabling Spring AOP to perform the necessary conversions + automatically on region operations. + + + + Upgraded to GemFire 7.0.1 and added namespace support for new AsyncEventQueue attributes + + + Added support for setting subscription interest policy on regions
diff --git a/docs/src/reference/docbook/reference/cache.xml b/docs/src/reference/docbook/reference/cache.xml index 63dc308b..1c92b9ca 100644 --- a/docs/src/reference/docbook/reference/cache.xml +++ b/docs/src/reference/docbook/reference/cache.xml @@ -117,6 +117,7 @@ pdx-read-serialized="false" message-sync-interval="1" search-timeout="300" + close="false" > <gfe:transaction-listener ref="myTransactionListener"/> diff --git a/docs/src/reference/docbook/reference/introduction.xml b/docs/src/reference/docbook/reference/introduction.xml index be6802db..e42e03a9 100644 --- a/docs/src/reference/docbook/reference/introduction.xml +++ b/docs/src/reference/docbook/reference/introduction.xml @@ -3,35 +3,37 @@ xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" - > - Document structure + xmlns:ns5="http://www.w3.org/2000/svg" + xmlns:ns4="http://www.w3.org/1998/Math/MathML" + xmlns:ns3="http://www.w3.org/1999/xhtml" + xmlns:ns="http://docbook.org/ns/docbook"> + Document structure - The following chapters explain the core functionality offered by - Spring Data GemFire. + The following chapters explain the core functionality offered by + Spring Data GemFire. - describes the configuration support - provided for bootstrapping, initializing, configuring, and accessing - GemFire caches, cache servers, regions, and related distributed system - components + describes the configuration support + provided for bootstrapping, initializing, configuring, and accessing GemFire + caches, cache servers, regions, and related distributed system + components - explains the integration between the GemFire - APIs and the various data access features available in Spring, such as - transaction management and exception translation. + explains the integration between the GemFire + APIs and the various data access features available in Spring, such as + transaction management and exception translation. - describes the enhancements for - GemFire (de)serialization and management of associated objects. + describes the enhancements for GemFire + (de)serialization and management of associated objects. - describes persistence mapping for POJOs - stored in GemFire using Spring Data + describes persistence mapping for POJOs + stored in GemFire using Spring Data - describes how to create and - use GemFire Repositories using Spring Data + describes how to create and use + GemFire Repositories using Spring Data - describes how to create and - use GemFire Functions using Spring Data + describes how to create and use + GemFire Functions using Spring Data - describes the samples provided with the - distribution to illustrate the various features available in Spring - GemFire. - - + describes the samples provided with the + distribution to illustrate the various features available in Spring Data + GemFire. + diff --git a/docs/src/reference/docbook/reference/region.xml b/docs/src/reference/docbook/reference/region.xml index fbf6a56c..e03c8dac 100644 --- a/docs/src/reference/docbook/reference/region.xml +++ b/docs/src/reference/docbook/reference/region.xml @@ -125,9 +125,7 @@ Common Region Attributes The following table(s) list attributes available for various - region types: - + region types:
Common Region Attributes @@ -163,7 +161,7 @@ close - boolean, default:true + boolean, default:false (Note: The default was true prior to 1.3.0) Indicates whether the region @@ -499,7 +497,17 @@ This is discussed further in +
+ Subscription Interest Policy + GemFire allows configuration of subscriptions to control peer to peer event handling. + Spring Data GemFire provides a <gfe:subscription/> to set the interest policy on replicated and partitioned regions to either ALL or CACHE_CONTENT. + + + <gfe:partitioned-region id="subscription-partition"> + <gfe:subscription type="CACHE_CONTENT"/> +</gfe:partitioned-region> +
Data Eviction and Overflowing @@ -782,7 +790,7 @@ and a nested resolver declaration --> client region while the latter defines connection pools to be used/shared by the various client regions. - Below is a typical client region configuration: + Below is a typical client region configuration:G <!-- client region using the default client-cache pool --> <gfe:client-region id="simple"> @@ -847,4 +855,30 @@ and a nested resolver declaration --> details.
+ +
+ JSON Support + + Gemfire 7.0 introduced support for caching JSON documents with OQL + query support. These are stored internally as PdxInstance types using the + JSONFormatter to perform conversion to and from JSON strings. Spring Data + GemFire provides a <gfe-data:json-region-autoproxy/> tag to enable a + Spring AOP component to advise appropropriate region operations, effectively + encapsulating the JSONFormatter, allowing your application to work directly + with JSON strings. In addition, Java objects written to JSON configured regions will + be automatically converted to JSON using the Jackson ObjectMapper. Reading these values will return a JSON string. + + + By default, <gfe-data:json-region-autoproxy/> will perform the conversion on all regions. To apply this feature to selected regions, provide a comma delimited list of + their ids via the region-refs attribute. Other attributes include a + pretty-print flag (false by default) and convert-returned-collections. By default the results of region + operations getAll() and values() will be converted for configured + regions. This is done by creating a parallel structure in local memory. This can incur significant overhead for large collections. Set this + flag to false to disable automatic conversion for these operation. + Certain region operations, specifically those that use GemFire's proprietary Region.Entry such as entries(boolean), entrySet(boolean) and getEntry() + type are not targeted for AOP advice. In addition, the entrySet() method which returns a Set<java.util.Map.Entry<?,?>> is not affected. + + This feature also works with seamlessly with GemfireTemplate operations, currently native QueryService operations are not supported. + +
diff --git a/src/main/java/org/springframework/data/gemfire/GemfireOperations.java b/src/main/java/org/springframework/data/gemfire/GemfireOperations.java new file mode 100644 index 00000000..ffdea646 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/GemfireOperations.java @@ -0,0 +1,121 @@ +/* + * Copyright 2002-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 java.util.Collection; +import java.util.Map; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.query.Query; +import com.gemstone.gemfire.cache.query.QueryService; +import com.gemstone.gemfire.cache.query.SelectResults; + +/** + * @author David Turanski + * + */ +public interface GemfireOperations { + + public abstract boolean containsKey(Object key); + + public abstract boolean containsKeyOnServer(Object key); + + public abstract boolean containsValue(Object value); + + public abstract boolean containsValueForKey(Object key); + + public abstract void create(K key, V value); + + public abstract V get(K key); + + public abstract V put(K key, V value); + + public abstract V putIfAbsent(K key, V value); + + public abstract V remove(K key); + + public abstract V replace(K key, V value); + + public abstract boolean replace(K key, V oldValue, V newValue); + + public abstract Map getAll(Collection keys); + + 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); + + /** + * 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. + * @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; + + /** + * 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}). + */ + public abstract T findUnique(String query, Object... params) throws InvalidDataAccessApiUsageException; + + public abstract 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 + * @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 + */ + public abstract T execute(GemfireCallback action, boolean exposeNativeRegion) throws DataAccessException; + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java b/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java index 4a0e4d52..a9273579 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java @@ -55,7 +55,7 @@ import com.gemstone.gemfire.internal.cache.LocalRegion; * * @author Costin Leau */ -public class GemfireTemplate extends GemfireAccessor { +public class GemfireTemplate extends GemfireAccessor implements GemfireOperations { private boolean exposeNativeRegion = false; @@ -96,6 +96,10 @@ public class GemfireTemplate extends GemfireAccessor { return this.exposeNativeRegion; } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#containsKey(java.lang.Object) + */ + @Override public boolean containsKey(final Object key) { return execute(new GemfireCallback() { public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { @@ -104,6 +108,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#containsKeyOnServer(java.lang.Object) + */ + @Override public boolean containsKeyOnServer(final Object key) { return execute(new GemfireCallback() { public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { @@ -112,6 +120,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#containsValue(java.lang.Object) + */ + @Override public boolean containsValue(final Object value) { return execute(new GemfireCallback() { public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { @@ -120,6 +132,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#containsValueForKey(java.lang.Object) + */ + @Override public boolean containsValueForKey(final Object key) { return execute(new GemfireCallback() { public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { @@ -128,6 +144,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#create(K, V) + */ + @Override public void create(final K key, final V value) { execute(new GemfireCallback() { @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -138,6 +158,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#get(K) + */ + @Override public V get(final K key) { return execute(new GemfireCallback() { @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -147,6 +171,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (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" }) @@ -156,6 +184,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (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" }) @@ -165,6 +197,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#remove(K) + */ + @Override public V remove(final K key) { return execute(new GemfireCallback() { @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -174,6 +210,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (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" }) @@ -183,6 +223,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (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" }) @@ -192,6 +236,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#getAll(java.util.Collection) + */ + @Override public Map getAll(final Collection keys) { return execute(new GemfireCallback>() { @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -201,6 +249,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#putAll(java.util.Map) + */ + @Override public void putAll(final Map map) { execute(new GemfireCallback() { @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -211,17 +263,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } - /** - * 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. + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#query(java.lang.String) */ + @Override public SelectResults query(final String query) { return execute(new GemfireCallback>() { @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -231,23 +276,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } - /** - * 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. - * @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}). + /* (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>() { @@ -265,22 +297,10 @@ public class GemfireTemplate extends GemfireAccessor { }); } - /** - * 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}). + /* (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" }) @@ -289,8 +309,13 @@ public class GemfireTemplate extends GemfireAccessor { Query q = queryService.newQuery(query); Object result = q.execute(params); if (result instanceof SelectResults) { - throw new InvalidDataAccessApiUsageException( + 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; } @@ -314,19 +339,18 @@ public class GemfireTemplate extends GemfireAccessor { } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#execute(org.springframework.data.gemfire.GemfireCallback) + */ + @Override public T execute(GemfireCallback action) throws DataAccessException { return execute(action, isExposeNativeRegion()); } - /** - * 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 + /* (non-Javadoc) + * @see org.springframework.data.gemfire.GemfireOperations#execute(org.springframework.data.gemfire.GemfireCallback, boolean) */ + @Override public T execute(GemfireCallback action, boolean exposeNativeRegion) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); try { diff --git a/src/main/java/org/springframework/data/gemfire/support/GemfireDaoSupport.java b/src/main/java/org/springframework/data/gemfire/support/GemfireDaoSupport.java index 43964473..da06affb 100644 --- a/src/main/java/org/springframework/data/gemfire/support/GemfireDaoSupport.java +++ b/src/main/java/org/springframework/data/gemfire/support/GemfireDaoSupport.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.support; import org.springframework.dao.support.DaoSupport; +import org.springframework.data.gemfire.GemfireOperations; import org.springframework.data.gemfire.GemfireTemplate; import org.springframework.util.Assert; @@ -37,7 +38,7 @@ import com.gemstone.gemfire.cache.Region; */ public class GemfireDaoSupport extends DaoSupport { - private GemfireTemplate gemfireTemplate; + private GemfireOperations gemfireTemplate; /** * Sets the GemFire Region to be used by this DAO. @@ -57,7 +58,7 @@ public class GemfireDaoSupport extends DaoSupport { * @return the new GemfireTemplate instance * @see #setRegion */ - protected GemfireTemplate createGemfireTemplate(Region region) { + protected GemfireOperations createGemfireTemplate(Region region) { return new GemfireTemplate(region); } @@ -66,7 +67,7 @@ public class GemfireDaoSupport extends DaoSupport { * as an alternative to specifying a GemFire {@link Region}. * @see #setRegion */ - public final void setGemfireTemplate(GemfireTemplate gemfireTemplate) { + public final void setGemfireTemplate(GemfireOperations gemfireTemplate) { this.gemfireTemplate = gemfireTemplate; } @@ -74,7 +75,7 @@ public class GemfireDaoSupport extends DaoSupport { * Return the GemfireTemplate for this DAO, pre-initialized * with the Region or set explicitly. */ - public final GemfireTemplate getGemfireTemplate() { + public final GemfireOperations getGemfireTemplate() { return gemfireTemplate; } diff --git a/src/main/java/org/springframework/data/gemfire/support/JSONRegionAdvice.java b/src/main/java/org/springframework/data/gemfire/support/JSONRegionAdvice.java index a5ee0447..5bef37da 100644 --- a/src/main/java/org/springframework/data/gemfire/support/JSONRegionAdvice.java +++ b/src/main/java/org/springframework/data/gemfire/support/JSONRegionAdvice.java @@ -26,9 +26,12 @@ import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.codehaus.jackson.map.ObjectMapper; +import org.springframework.data.gemfire.GemfireTemplate; import org.springframework.util.CollectionUtils; import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.query.SelectResults; +import com.gemstone.gemfire.cache.query.internal.ResultsBag; import com.gemstone.gemfire.pdx.JSONFormatter; import com.gemstone.gemfire.pdx.PdxInstance; @@ -84,7 +87,6 @@ public class JSONRegionAdvice { + "execution(* com.gemstone.gemfire.cache.Region.putIfAbsent(..)) ||" + "execution(* com.gemstone.gemfire.cache.Region.replace(..))") public Object put(ProceedingJoinPoint pjp) { - System.out.println("intercepted " + pjp.getSignature().getName()); boolean JSONRegion = isIncludedSONRegion(pjp.getTarget()); Object retVal = null; @@ -94,6 +96,8 @@ public class JSONRegionAdvice { Object val = newArgs[1]; newArgs[1] = convertArgumentToPdxInstance(val); retVal = pjp.proceed(newArgs); + log.debug("converting " + retVal + " to JSON string"); + retVal = convertPdxInstanceToJSONString(retVal); } else { retVal = pjp.proceed(); } @@ -128,22 +132,22 @@ public class JSONRegionAdvice { } @Around("execution(* com.gemstone.gemfire.cache.Region.get(..)) " - + "|| execution(* com.gemstone.gemfire.cache.Region.selectValue(..))") + + "|| execution(* com.gemstone.gemfire.cache.Region.selectValue(..))" + + "|| execution(* com.gemstone.gemfire.cache.Region.remove(..))") public Object get(ProceedingJoinPoint pjp) { Object retVal = null; try { if (isIncludedSONRegion(pjp.getTarget())) { retVal = pjp.proceed(); log.debug("converting " + retVal + " to JSON string"); - return convertPdxInstanceToJSONString(retVal); + retVal = convertPdxInstanceToJSONString(retVal); } else { - return pjp.proceed(); + retVal = pjp.proceed(); } } catch (Throwable t) { handleThrowable(t); } return retVal; - } @SuppressWarnings("unchecked") @@ -185,6 +189,35 @@ public class JSONRegionAdvice { } return result; } + + @Around("execution(* org.springframework.data.gemfire.GemfireOperations.find(..)) " + + "|| execution(* org.springframework.data.gemfire.GemfireOperations.findUnique(..)) " + + "|| execution(* org.springframework.data.gemfire.GemfireOperations.query(..))") + public Object templateQuery(ProceedingJoinPoint pjp) { + GemfireTemplate template = (GemfireTemplate) pjp.getTarget(); + boolean jsonRegion = isIncludedSONRegion(template.getRegion()); + Object retVal = null; + try { + if (jsonRegion) { + retVal = pjp.proceed(); + if (retVal instanceof SelectResults && convertReturnedCollections ) { + ResultsBag resultsBag = new ResultsBag(); + for (Object obj: (SelectResults)retVal) { + resultsBag.add(convertPdxInstanceToJSONString(obj)); + } + retVal = resultsBag; + } else { + retVal = convertPdxInstanceToJSONString(retVal); + } + } else { + retVal = pjp.proceed(); + } + } catch (Throwable t) { + handleThrowable(t); + } + return retVal; + } + private PdxInstance convertArgumentToPdxInstance(Object value) { PdxInstance val = null; @@ -220,9 +253,9 @@ public class JSONRegionAdvice { Object result = retVal; if (retVal != null && retVal instanceof PdxInstance) { result = JSONFormatter.toJSON((PdxInstance) retVal); - } - if (!prettyPrint) { - result = flattenString(result); + if (!prettyPrint) { + result = flattenString(result); + } } return result; } diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java index f690ddeb..f03c99ee 100644 --- a/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java @@ -52,7 +52,7 @@ public class GemfireTemplateTest { private static final String SINGLE_QUERY = "(select * from /simple).size"; - @Autowired GemfireTemplate template; + @Autowired GemfireOperations template; @SuppressWarnings("rawtypes") @Before diff --git a/src/test/java/org/springframework/data/gemfire/support/GemfireDaoSupportTests.java b/src/test/java/org/springframework/data/gemfire/support/GemfireDaoSupportTests.java index 2387709f..2827fc79 100644 --- a/src/test/java/org/springframework/data/gemfire/support/GemfireDaoSupportTests.java +++ b/src/test/java/org/springframework/data/gemfire/support/GemfireDaoSupportTests.java @@ -20,6 +20,7 @@ import java.util.List; import junit.framework.TestCase; +import org.springframework.data.gemfire.GemfireOperations; import org.springframework.data.gemfire.GemfireTemplate; /** @@ -30,7 +31,7 @@ public class GemfireDaoSupportTests extends TestCase { @SuppressWarnings("rawtypes") public void testGemfireDaoSupportWithTemplate() throws Exception { - GemfireTemplate template = new GemfireTemplate(); + GemfireOperations template = new GemfireTemplate(); final List test = new ArrayList(); GemfireDaoSupport dao = new GemfireDaoSupport() { @SuppressWarnings("unchecked") diff --git a/src/test/java/org/springframework/data/gemfire/support/JSONRegionAdviceTest.java b/src/test/java/org/springframework/data/gemfire/support/JSONRegionAdviceTest.java index c3e84f5d..d6bae478 100644 --- a/src/test/java/org/springframework/data/gemfire/support/JSONRegionAdviceTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/JSONRegionAdviceTest.java @@ -24,14 +24,16 @@ import javax.annotation.Resource; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.JsonMappingException; -import org.codehaus.jackson.map.ObjectMapper; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.gemfire.GemfireOperations; import org.springframework.data.gemfire.repository.sample.Person; 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; /** * @author David Turanski @@ -40,17 +42,28 @@ import com.gemstone.gemfire.cache.Region; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class JSONRegionAdviceTest { + @SuppressWarnings("rawtypes") @Resource(name="someRegion") private Region region; + + @Autowired + GemfireOperations template; + @Test public void testPutString() { String json = "{\"hello\":\"world\"}"; + region.put("key",json); + Object result = region.put("key",json); + assertEquals(json,result); + region.create("key2",json); + System.out.println(region.get("key")); assertEquals(json,region.get("key")); } + @SuppressWarnings("unchecked") @Test public void testPutAll() { Map map = new HashMap(); @@ -69,6 +82,32 @@ public class JSONRegionAdviceTest { region.put("dave",dave); String json = (String)region.get("dave"); assertEquals(json,"{\"id\":1,\"firstname\":\"Dave\",\"lastname\":\"Turanski\",\"address\":null}",json); + Object result = region.put("dave",dave); + assertEquals("{\"id\":1,\"firstname\":\"Dave\",\"lastname\":\"Turanski\",\"address\":null}",result); + } + + @Test + public void testTemplateFindUnique() { + Person dave = new Person(1L,"Dave","Turanski"); + region.put("dave",dave); + String json = (String) template.findUnique("Select * from /someRegion where firstname=$1","Dave"); + assertEquals("{\"id\":1,\"firstname\":\"Dave\",\"lastname\":\"Turanski\",\"address\":null}",json); + } + + @Test + public void testTemplateFind() { + Person dave = new Person(1L,"Dave","Turanski"); + region.put("dave",dave); + SelectResults results = template.find("Select * from /someRegion where firstname=$1","Dave"); + assertEquals("{\"id\":1,\"firstname\":\"Dave\",\"lastname\":\"Turanski\",\"address\":null}",results.iterator().next()); + } + + @Test + public void testTemplateQuery() { + Person dave = new Person(1L,"Dave","Turanski"); + region.put("dave",dave); + SelectResults results = template.query("firstname='Dave'"); + assertEquals("{\"id\":1,\"firstname\":\"Dave\",\"lastname\":\"Turanski\",\"address\":null}",results.iterator().next()); } } diff --git a/src/test/resources/org/springframework/data/gemfire/config/subscription-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/subscription-ns.xml index aa35ba0a..79c3a368 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/subscription-ns.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/subscription-ns.xml @@ -7,18 +7,18 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd"> - + - + - - + + diff --git a/src/test/resources/org/springframework/data/gemfire/support/JSONRegionAdviceTest-context.xml b/src/test/resources/org/springframework/data/gemfire/support/JSONRegionAdviceTest-context.xml index 37661fab..49fa2de3 100644 --- a/src/test/resources/org/springframework/data/gemfire/support/JSONRegionAdviceTest-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/support/JSONRegionAdviceTest-context.xml @@ -22,6 +22,9 @@ - - + + + + +