Updated reference and JSON support for GemfireTemplate queries

This commit is contained in:
David Turanski
2013-03-13 18:00:15 -04:00
parent fb18299759
commit 0e81e9d4c8
14 changed files with 382 additions and 106 deletions

View File

@@ -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)

View File

@@ -17,7 +17,7 @@
</note>
<section id="new-in-1-3-0">
<title>New in the 1.3.0.Release</title>
<title>New in the 1.3.0 Release</title>
<itemizedlist>
<listitem>
@@ -29,9 +29,25 @@
</listitem>
<listitem>
<para>A <tag>&lt;datasource&gt;</tag> tag has been added to the
<para>We have added a <tag>&lt;datasource&gt;</tag> tag to the
<emphasis>gfe-data</emphasis> XML namespace. This simplifies
establishing a basic client <link linkend="data-access:datasource">connection</link> to a GemFire data grid.</para>
establishing a basic client <link
linkend="data-access:datasource">connection</link> to a GemFire data
grid.</para>
</listitem>
<listitem>
<para>To <link linkend="bootstrap:region:json">support JSON</link> features introduced in GemFire 7.0, we have
added a ,<tag>&lt;json-region-autoproxy&gt;</tag> tag to the <emphasis>gfe-data</emphasis> XML
namespace, enabling Spring AOP to perform the necessary conversions
automatically on region operations.</para>
</listitem>
<listitem>
<para>Upgraded to GemFire 7.0.1 and added namespace support for new AsyncEventQueue attributes</para>
</listitem>
<listitem>
<para>Added support for setting subscription interest policy on regions</para>
</listitem>
</itemizedlist>
</section>

View File

@@ -117,6 +117,7 @@
pdx-read-serialized="false"
message-sync-interval="1"
search-timeout="300"
close="false"
&gt;
<co id="gfe#transaction#listener"/>&lt;gfe:transaction-listener ref="myTransactionListener"/&gt;

View File

@@ -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"
>
<title>Document structure</title>
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">
<title>Document structure</title>
<para>The following chapters explain the core functionality offered by
Spring Data GemFire.</para>
<para>The following chapters explain the core functionality offered by
Spring Data GemFire.</para>
<para><xref linkend="bootstrap"/> describes the configuration support
provided for bootstrapping, initializing, configuring, and accessing
GemFire caches, cache servers, regions, and related distributed system
components</para>
<para><xref linkend="bootstrap"/> describes the configuration support
provided for bootstrapping, initializing, configuring, and accessing GemFire
caches, cache servers, regions, and related distributed system
components</para>
<para><xref linkend="apis"/> explains the integration between the GemFire
APIs and the various data access features available in Spring, such as
transaction management and exception translation.</para>
<para><xref linkend="apis"/> explains the integration between the GemFire
APIs and the various data access features available in Spring, such as
transaction management and exception translation.</para>
<para><xref linkend="serialization"/> describes the enhancements for
GemFire (de)serialization and management of associated objects.</para>
<para><xref linkend="serialization"/> describes the enhancements for GemFire
(de)serialization and management of associated objects.</para>
<para><xref linkend="mapping"/> describes persistence mapping for POJOs
stored in GemFire using Spring Data</para>
<para><xref linkend="mapping"/> describes persistence mapping for POJOs
stored in GemFire using Spring Data</para>
<para><xref linkend="gemfire-repositories"/> describes how to create and
use GemFire Repositories using Spring Data</para>
<para><xref linkend="gemfire-repositories"/> describes how to create and use
GemFire Repositories using Spring Data</para>
<para><xref linkend="function-annotations"/> describes how to create and
use GemFire Functions using Spring Data</para>
<para><xref linkend="function-annotations"/> describes how to create and use
GemFire Functions using Spring Data</para>
<para><xref linkend="samples"/> describes the samples provided with the
distribution to illustrate the various features available in Spring
GemFire.</para>
</chapter>
<para><xref linkend="samples"/> describes the samples provided with the
distribution to illustrate the various features available in Spring Data
GemFire.</para>
</chapter>

View File

@@ -125,9 +125,7 @@
<title>Common Region Attributes</title>
<para>The following table(s) list attributes available for various
region types:
<table
id="bootstrap:region:common:attributes:table">
region types: <table id="bootstrap:region:common:attributes:table">
<title>Common Region Attributes</title>
<tgroup cols="3">
@@ -163,7 +161,7 @@
<entry>close</entry>
<entry spanname="values">
<emphasis>boolean, default:true</emphasis>
<emphasis>boolean, default:false (Note: The default was true prior to 1.3.0)</emphasis>
</entry>
<entry spanname="description">Indicates whether the region
@@ -499,7 +497,17 @@
<para>This is discussed further in <xref
linkend="bootstrap-diskstore"/></para>
</section>
<section id="bootstrap:region:subscription">
<title>Subscription Interest Policy</title>
<para>GemFire allows configuration of subscriptions to control <ulink url="http://pubs.vmware.com//vfabricNoSuite/topic/com.vmware.vfabric.gemfire.7.0/developing/events/configure_p2p_event_messaging.html">peer to peer event handling</ulink>.
Spring Data GemFire provides a <tag>&lt;gfe:subscription/&gt;</tag> to set the interest policy on replicated and partitioned regions to either <literal>ALL</literal> or <literal>CACHE_CONTENT</literal>.
</para>
<programlisting language="xml">&lt;gfe:partitioned-region id="subscription-partition"&gt;
&lt;gfe:subscription type="CACHE_CONTENT"/&gt;
&lt;/gfe:partitioned-region&gt;</programlisting>
</section>
<section id="bootstrap:region:eviction">
<title>Data Eviction and Overflowing</title>
@@ -782,7 +790,7 @@ and a nested resolver declaration --&gt;
client region while the latter defines connection pools to be used/shared
by the various client regions.</para>
<para>Below is a typical client region configuration:</para>
<para>Below is a typical client region configuration:G</para>
<programlisting language="xml">&lt;!-- client region using the default client-cache pool --&gt;
&lt;gfe:client-region id="simple"&gt;
@@ -847,4 +855,30 @@ and a nested resolver declaration --&gt;
details.</para>
</section>
</section>
<section id="bootstrap:region:json">
<title>JSON Support</title>
<para>Gemfire 7.0 introduced support for caching JSON documents with OQL
query support. These are stored internally as <ulink url="http://www.vmware.com/support/developer/vfabric-gemfire/700-api/com/gemstone/gemfire/pdx/PdxInstance.html">PdxInstance</ulink> types using the
<ulink url="http://www.vmware.com/support/developer/vfabric-gemfire/700-api/com/gemstone/gemfire/pdx/JSONFormatter.html">JSONFormatter</ulink> to perform conversion to and from JSON strings. Spring Data
GemFire provides a <tag>&lt;gfe-data:json-region-autoproxy/&gt;</tag> tag to enable a
<ulink url="http://static.springsource.org/spring/docs/current/spring-framework-reference/htmlsingle/#aop-introduction">Spring AOP</ulink> 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.
</para>
<para>
By default, <tag>&lt;gfe-data:json-region-autoproxy/&gt;</tag> will perform the conversion on all regions. To apply this feature to selected regions, provide a comma delimited list of
their ids via the <literal>region-refs</literal> attribute. Other attributes include a
<literal>pretty-print</literal> flag (false by default) and <literal>convert-returned-collections</literal>. 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.
<note>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&lt;java.util.Map.Entry&lt;?,?&gt;&gt; is not affected.</note>
</para>
<para>This feature also works with seamlessly with GemfireTemplate operations, currently native QueryService operations are not supported.
</para>
</section>
</section>

View File

@@ -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 <K, V> void create(K key, V value);
public abstract <K, V> V get(K key);
public abstract <K, V> V put(K key, V value);
public abstract <K, V> V putIfAbsent(K key, V value);
public abstract <K, V> V remove(K key);
public abstract <K, V> V replace(K key, V value);
public abstract <K, V> boolean replace(K key, V oldValue, V newValue);
public abstract <K, V> Map<K, V> getAll(Collection<?> keys);
public abstract <K, V> void putAll(Map<? extends K, ? extends V> 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 <E> SelectResults<E> 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...)}.
* <p/>
* As oppose, to the {@link #query(String)} method, this method allows for more generic queries (against multiple regions even) to be executed.
*
* <p/>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 <E> SelectResults<E> 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...)}.
* <p/>
* As oppose, to the {@link #query(String)} method, this method allows for more generic queries (against multiple regions even) to be executed.
*
* <p/>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> T findUnique(String query, Object... params) throws InvalidDataAccessApiUsageException;
public abstract <T> T execute(GemfireCallback<T> 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 <code>null</code>
* @throws org.springframework.dao.DataAccessException in case of GemFire errors
*/
public abstract <T> T execute(GemfireCallback<T> action, boolean exposeNativeRegion) throws DataAccessException;
}

View File

@@ -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<Boolean>() {
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<Boolean>() {
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<Boolean>() {
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<Boolean>() {
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 <K, V> void create(final K key, final V value) {
execute(new GemfireCallback<Object>() {
@SuppressWarnings({ "unchecked", "rawtypes" })
@@ -138,6 +158,10 @@ public class GemfireTemplate extends GemfireAccessor {
});
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.GemfireOperations#get(K)
*/
@Override
public <K, V> V get(final K key) {
return execute(new GemfireCallback<V>() {
@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 <K, V> V put(final K key, final V value) {
return execute(new GemfireCallback<V>() {
@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 <K, V> V putIfAbsent(final K key, final V value) {
return execute(new GemfireCallback<V>() {
@SuppressWarnings({ "unchecked", "rawtypes" })
@@ -165,6 +197,10 @@ public class GemfireTemplate extends GemfireAccessor {
});
}
/* (non-Javadoc)
* @see org.springframework.data.gemfire.GemfireOperations#remove(K)
*/
@Override
public <K, V> V remove(final K key) {
return execute(new GemfireCallback<V>() {
@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 <K, V> V replace(final K key, final V value) {
return execute(new GemfireCallback<V>() {
@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 <K, V> boolean replace(final K key, final V oldValue, final V newValue) {
return execute(new GemfireCallback<Boolean>() {
@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 <K, V> Map<K, V> getAll(final Collection<?> keys) {
return execute(new GemfireCallback<Map<K, V>>() {
@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 <K, V> void putAll(final Map<? extends K, ? extends V> map) {
execute(new GemfireCallback<Object>() {
@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 <E> SelectResults<E> query(final String query) {
return execute(new GemfireCallback<SelectResults<E>>() {
@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...)}.
* <p/>
* As oppose, to the {@link #query(String)} method, this method allows for more generic queries (against multiple regions even) to be executed.
*
* <p/>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 <E> SelectResults<E> find(final String query, final Object... params)
throws InvalidDataAccessApiUsageException {
return execute(new GemfireCallback<SelectResults<E>>() {
@@ -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...)}.
* <p/>
* As oppose, to the {@link #query(String)} method, this method allows for more generic queries (against multiple regions even) to be executed.
*
* <p/>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> T findUnique(final String query, final Object... params) throws InvalidDataAccessApiUsageException {
return execute(new GemfireCallback<T>() {
@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<T> selectResults = (SelectResults<T>)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> T execute(GemfireCallback<T> 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 <code>null</code>
* @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> T execute(GemfireCallback<T> action, boolean exposeNativeRegion) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
try {

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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")

View File

@@ -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<String,String> map = new HashMap<String,String>();
@@ -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<String> 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<String> results = template.query("firstname='Dave'");
assertEquals("{\"id\":1,\"firstname\":\"Dave\",\"lastname\":\"Turanski\",\"address\":null}",results.iterator().next());
}
}

View File

@@ -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">
<gfe:cache/>
<gfe:replicated-region id="replicALL">
<gfe:subscription type="ALL"/>
</gfe:replicated-region>
<gfe:partitioned-region id="partCACHE_CONTENT">
<gfe:subscription type="CACHE_CONTENT"/>
<gfe:eviction threshold="70"/>
</gfe:partitioned-region>
<gfe:partitioned-region id="partDEFAULT">
<gfe:subscription/>
</gfe:partitioned-region>

View File

@@ -22,6 +22,9 @@
<!-- <bean class="org.springframework.data.gemfire.support.JSONRegionAdvice" /> -->
<gfe:cache properties-ref="props"/>
<gfe:replicated-region id="someRegion" />
<gfe:replicated-region id="someRegion"/>
<bean id="template" class="org.springframework.data.gemfire.GemfireTemplate">
<constructor-arg ref="someRegion"/>
</bean>
</beans>