forked from spring-projects/spring-data-gemfire
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Costin Leau
committed
Aug 27, 2011
1 parent
f3abb84
commit a0dc7cb
Showing
2 changed files
with
137 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="apis:cq-container"> | ||
<title>GemFire Continuous Query Container</title> | ||
|
||
<para>A powerful functionality offered by GemFire is | ||
<ulink url="http://community.gemstone.com/display/gemfire/Continuous+Querying">continuous querying</ulink> (or CQ). | ||
In short, CQ allows one to create a query and automatically be notified when new data that gets added to GemFire matches the query. | ||
|
||
Spring GemFire provides dedicated support for CQs through the <literal>org.springframework.data.gemfire.listener</literal> package and | ||
its <emphasis>listener container</emphasis>; very similar in functionality | ||
and naming to the JMS integration in Spring Framework; in fact, users familiar with the JMS support in Spring, should | ||
feel right at home. Basically SGF allows methods on POJOs to become end-points for CQ - simply define the query and indicate the method | ||
that should be notified when there is a match - SGF takes care of the rest. This of Java EE's message-driven bean style, but without any | ||
requirement for base class or interface implementations, based on GemFire.</para> | ||
|
||
<note> | ||
<para>Currently, continuous queries are supported by GemFire only in client/server topologies. Additionally the pool used is required to have the | ||
<literal>subscription</literal> property enabled. Please refer to the documentation for more information.</para> | ||
</note> | ||
|
||
<section id="apis:cq-container:containers"> | ||
<title>Continuous Query Listener Container</title> | ||
|
||
<para>SGF simplifies the creation, registration, life-cycle and dispatch of CQs by taking care of the infrastructure around them through | ||
<classname>ContinuousQueryListenerContainer</classname> which does all the heavy lifting on behalf of the user - | ||
users familiar with EJB and JMS should find the concepts familiar as it is designed as close as possible to the | ||
support in Spring Framework and its message-driven POJOs (MDPs)</para> | ||
|
||
<para><classname>ContinuousQueryListenerContainer</classname> acts as an event (or message) listener container; it is used to receive the events | ||
from the registered CQs and drive the POJOs that are injected into it. The listener container is responsible for all threading of message | ||
reception and dispatches into the listener for processing. It acts as the intermediary between an EDP (Event Driven POJO) and the event provider | ||
and takes care of creation and registration of CQs (to receive events), resource acquisition and release, exception conversion and suchlike. | ||
This allows you as an application developer to write the (possibly complex) business logic associated with receiving an event (and reacting to it), | ||
and delegates boilerplate GemFire infrastructure concerns to the framework. | ||
</para> | ||
|
||
<para>The container is fully customizable - one can chose either to use the CQ thread to perform the dispatch (synchronous delivery) or a new thread | ||
(from an existing pool for examples) for an asynch approach by defining the suitable <interfacename>java.util.concurrent.Executor</interfacename> | ||
(or Spring's <interfacename>TaskExecutor</interfacename>). Depending on the load, the number of listeners or the runtime | ||
environment, one should change or tweak the executor to better serve her needs - in particular in managed environments (such as app servers), it is | ||
highly recommended to pick a a proper <interfacename>TaskExecutor</interfacename> to take advantage of its runtime.</para> | ||
</section> | ||
|
||
<section id="apis:cq-container:adapter"> | ||
<title>The <classname>ContinuousQueryListenerAdapter</classname> and <interfacename>ContinuousQueryListener</interfacename></title> | ||
|
||
<para>The <classname>ContinuousQueryListenerAdapter</classname> class is the | ||
final component in SGF CQ support: in a nutshell, it allows you to expose almost <emphasis>any</emphasis> class | ||
as a EDP (there are of course some constraints) - it implements <interfacename>ContinuousQueryListener</interfacename>, a simpler listener interface | ||
similar to GemFire <ulink url="http://www.gemstone.com/docs/6.5.1/product/docs/japi/com/gemstone/gemfire/cache/query/CqListener.html">CqListener</ulink>.</para> | ||
|
||
<para>Consider the following interface definition. Notice the | ||
various event handling methods and their parameters:</para> | ||
|
||
<programlisting language="java">public interface EventDelegate { | ||
void handleEvent(CqEvent event); | ||
void handleEvent(Operation baseOp); | ||
void handleEvent(Object key); | ||
void handleEvent(Object key, Object newValue); | ||
void handleEvent(Throwable th); | ||
void handleQuery(CqQuery cq); | ||
void handleEvent(CqEvent event, Operation baseOp, byte[] deltaValue); | ||
void handleEvent(CqEvent event, Operation baseOp, Operation queryOp, Object key, Object newValue); | ||
}</programlisting> | ||
|
||
<programlisting language="java">public class DefaultEventDelegate implements EventDelegate { | ||
<lineannotation>// implementation elided for clarity...</lineannotation> | ||
}</programlisting> | ||
|
||
<para>In particular, note how the above implementation of the | ||
<interfacename>EventDelegate</interfacename> interface (the above | ||
<classname>DefaultEventDelegate</classname> class) has | ||
<emphasis>no</emphasis> GemFire dependencies at all. It truly is a POJO that | ||
we will make into an EDP via the following configuration (note that the class doesn't have to implement an interface, | ||
one is present only to better show case the decoupling between contract and implementation).</para> | ||
|
||
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> | ||
<beans xmlns="http://www.springframework.org/schema/beans" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
<lineannotation>xmlns:gfe="http://www.springframework.org/schema/gemfire"</lineannotation> | ||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd | ||
<lineannotation>http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd"</lineannotation>> | ||
|
||
<!-- create a client-pool that uses a pool with subscription enabled --> | ||
<gfe:client-cache pool-name="client"/> | ||
|
||
<gfe:pool id="client" subscription-enabled="true"> | ||
<gfe:server host="localhost" port="40404"/> | ||
</gfe:pool> | ||
|
||
<gfe:cq-listener-container> | ||
<!-- default handle method --> | ||
<gfe:listener ref="listener" query="SELECT * from /region"/ > | ||
<gfe:listener ref="another-listener" query="SELECT * from /another-region" name="my-query" method="handleQuery"/> | ||
</gfe:cq-listener-container> | ||
|
||
<bean id="listener" class="gemfireexample.DefaultMessageDelegate"/> | ||
<bean id="another-listener" class="gemfireexample.DefaultMessageDelegate"/> | ||
... | ||
<beans></programlisting> | ||
<note>The example above shows some of the various forms that a listener can have; at its minimum the listener reference and the actual query definition are required. It's possible however to specify | ||
a name for the resulting continuous query (useful for monitoring) but also the name of the method (the default is <literal>handleEvent</literal>). The specified method can have various | ||
argument types, the <interfacename>EventDelegate</interfacename> interface lists the allowed types.</note> | ||
|
||
<para>The example above uses the SGF namespace to declare the event listener container and automatically register the POJOs as listeners. The full blown, <emphasis>beans</emphasis> definition | ||
is displayed below:</para> | ||
|
||
<programlisting language="xml"><lineannotation><!-- this is the Event Driven POJO (MDP) --></lineannotation> | ||
<emphasis role="bold"><bean id="eventListener" class="org.springframework.data.gemfire.listener.adapter.ContinuousQueryListenerAdapter"></emphasis> | ||
<constructor-arg> | ||
<bean class="gemfireexample.DefaultEventDelegate"/> | ||
</constructor-arg> | ||
</bean> | ||
|
||
<lineannotation><!-- and this is the event listener container... --></lineannotation> | ||
<bean id="gemfireListenerContainer" class="org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer"> | ||
<property name="cache" ref="gemfire-cache"/> | ||
<property name="queryListeners"> | ||
<lineannotation><!-- set of listeners --></lineannotation> | ||
<set> | ||
<bean class="org.springframework.data.gemfire.listener.ContinuousQueryDefinition" > | ||
<constructor-arg value="SELECT * from /region" /> | ||
<constructor-arg ref="eventListener" /> | ||
</bean> | ||
</set> | ||
</property> | ||
</bean></programlisting> | ||
|
||
<para>Each time an event is received, the adapter automatically performs | ||
type translation between the GemFire event and the required method argument(s) transparently. Any exception caused by the method invocation | ||
is caught and handled by the container (by default, being logged). | ||
</para> | ||
</section> | ||
</section> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters