Permalink
Browse files

Add the CQ with JavaConfig example.

  • Loading branch information...
jxblum committed Aug 17, 2017
1 parent 665ab12 commit 2559042197c4e56606c0bbc803567834a8a050fc
View
@@ -1,35 +1,28 @@
description = 'Spring Data GemFire Advanced Examples'
-project('gateway') {
- description = 'Spring Data GemFire Gateway Example'
-
- def env = System.getenv()
-
- dependencies {
- compile project(':spring-gemfire-examples-common')
- }
-}
-
project('gatewayV7') {
- description = 'Spring Data GemFire Gateway (Version 7) Example'
- def env = System.getenv()
+ description = 'Spring Data GemFire Gateway (Version 7) Example'
dependencies {
compile project(':spring-gemfire-examples-common')
}
}
project('locator-failover') {
+
description = 'Spring Data GemFire Locator Failover Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
}
}
project('server-failover') {
+
description = 'Spring Data GemFire Server Failover Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
}
View
@@ -1,22 +1,28 @@
description = 'Spring Data GemFire Basic Examples'
project('replicated') {
+
description = 'Spring Data GemFire Replicated Region (p2p) Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
}
}
project('replicated-cs') {
+
description = 'Spring Data GemFire Replicated Region (Client Server) Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
}
}
project('partitioned') {
+
description = 'Spring Data GemFire Partitioned Region Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
@@ -26,7 +32,9 @@ project('partitioned') {
}
project('persistence') {
+
description = 'Spring Data GemFire Persistence Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
@@ -36,7 +44,9 @@ project('persistence') {
}
project('write-through') {
+
description = 'Spring Data GemFire Write Through Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
@@ -52,7 +62,9 @@ project('write-through') {
}
project('function') {
+
description = 'Spring Data GemFire Function Execution Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
@@ -62,7 +74,9 @@ project('function') {
}
project('annotated-function') {
+
description = 'Spring Data GemFire Function Execution with Annotations Example'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
@@ -72,7 +86,9 @@ project('annotated-function') {
}
project('java-config') {
+
description = 'Spring Data GemFire Configuration Example using Spring Java-based Container Configuration'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
@@ -82,11 +98,16 @@ project('java-config') {
}
project('cq-with-javaconfig') {
+
description = 'Continuous Query example using the Spring Data GemFire ContinuousQueryListenerContainer configured with JavaConfig'
+
dependencies {
compile project(':spring-gemfire-examples-common')
compile "org.springframework:spring-aop:$springVersion"
compile "org.springframework:spring-context-support:$springVersion"
compile "org.springframework:spring-tx:$springVersion"
+ compile ("org.springframework.boot:spring-boot-starter:$springBootVersion") {
+ exclude group: "ch.qos.logback", module: "logback-classic"
+ }
}
}
@@ -0,0 +1,53 @@
+GemFire Continuous Query (CQ) Configured with Spring JavaConfig
+===============================================================
+
+This example demonstrates GemFire's [Continuous Query (CQ)](http://gemfire.docs.pivotal.io/geode/developing/continuous_querying/chapter_overview.html) functionality.
+Specifically, this example shows how to use _Spring's_ [Java-based Container Configuration](http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-java)
+along with _Spring Data GemFire's_ [ContinuousQueryListenerContainer](http://docs.spring.io/spring-data-gemfire/docs/current/reference/html/#apis:cq-container)
+declared in JavaConfig to define cache client _Continuous Queries_ (CQ),
+register for notifications and process CQ events.
+
+This examples uses GemFire's [client/server](http://gemfire.docs.pivotal.io/geode/topologies_and_comm/cs_configuration/chapter_overview.html)
+topology.
+
+The `Server` class in this example is a _Spring Boot_ application that bootstraps
+an embedded GemFire Server (peer cache member of the GemFire cluster/distributed system)
+and starts a GemFire `CacheServer` allowing cache clients to connect.
+In addition, it also creates a `/Orders` _Region_ in which `Orders`
+will be placed and CQ events generated.
+
+The application simulates `Orders` from `Customers` using _Spring's_ [scheduling infrastructure](http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#scheduling),
+placing `Orders` into the `/Orders` _Region_.
+
+The `Client` class in this example is also a _Spring Boot_ application
+as well as a GemFire cache client. It connects to the GemFire `CacheServer` directly
+using the default `CacheServer's` host and port (i.e. 40404).
+
+The client registers 2 CQs, 1 to capture events for `Orders` under $1000
+and another for `Orders` over $2000. Both the client and server log
+the entries in the `/Orders` _Region_. The `Server` does so with
+a `CacheListener` and the client does so using a SDG `ContinuousQueryListener`.
+
+To run this example, open a command window, go to the the `spring-gemfire-examples` root directory, and type:
+
+ ./gradlew -q run-cq-with-javaconfig -Pmain=server.Server
+
+In another window, type:
+
+ ./gradlew -q run-cq-with-javaconfig -Pmain=client.Client
+
+Or, to run from your IDE, execute one of the following tasks once:
+
+ ./gradlew eclipse
+ ./gradlew idea
+
+Then import the project into your IDE and run the above classes.
+
+# Additional Details
+
+An implementation of SDG's `ContinuousQueryListener` is a POJO (albeit dependent only on the GemFire type `CQEvent`).
+It is not required to implement any specific interfaces, but it must provide appropriate method signatures
+so the `ConitnuousQueryListenerContainer` can delegate `CQEvents` to it.
+
+Additionally, the cache client, _Spring Boot_ application's `Pool`
+must be configured with `subscription-enabled='true'`.
@@ -1,11 +0,0 @@
-package org.springframework.data.gemfire.examples;
-
-/**
- * The Server class...
- *
- * @author John Blum
- * @since 1.0.0
- */
-public class Server {
-
-}
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2017 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.examples.client;
+
+import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
+
+import java.util.Scanner;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
+import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
+import org.springframework.data.gemfire.examples.domain.Customer;
+import org.springframework.data.gemfire.examples.domain.Order;
+import org.springframework.data.gemfire.examples.domain.Product;
+import org.springframework.data.gemfire.listener.ContinuousQueryDefinition;
+import org.springframework.data.gemfire.listener.ContinuousQueryListener;
+import org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer;
+
+import org.apache.geode.cache.GemFireCache;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+
+/**
+ * The {@link Client} class is a Spring Boot, GemFire cache client application demonstrating how to
+ * register GemFire Continuous Queries (CQ) using Spring Data GemFire's {@link ContinuousQueryListenerContainer}
+ * in JavaConfig.
+ *
+ * @author John Blum
+ * @see org.springframework.boot.SpringApplication
+ * @see org.springframework.boot.autoconfigure.SpringBootApplication
+ * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
+ * @see org.springframework.data.gemfire.examples.domain.Customer
+ * @see org.springframework.data.gemfire.examples.domain.Order
+ * @see org.springframework.data.gemfire.examples.domain.Product
+ * @see org.springframework.data.gemfire.listener.ContinuousQueryDefinition
+ * @see org.springframework.data.gemfire.listener.ContinuousQueryListener
+ * @see org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer
+ * @see <a href="http://gemfire.docs.pivotal.io/geode/developing/continuous_querying/chapter_overview.html">Continuous Query</a>
+ * @since 2.0.0
+ */
+@SpringBootApplication
+@ClientCacheApplication(name = "GemFireContinuousQueryClient", subscriptionEnabled = true)
+@SuppressWarnings("unused")
+public class Client {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Client.class, args);
+ promptForInputToExit();
+ }
+
+ private static void promptForInputToExit() {
+ System.err.println("Press <ENTER> to exit");
+ new Scanner(System.in).nextLine();
+ }
+
+ @Bean(name = "Customers")
+ ClientRegionFactoryBean<Long, Product> customersRegion(GemFireCache gemfireCache) {
+
+ ClientRegionFactoryBean<Long, Product> customers = new ClientRegionFactoryBean<>();
+
+ customers.setCache(gemfireCache);
+ customers.setClose(true);
+ customers.setShortcut(ClientRegionShortcut.PROXY);
+
+ return customers;
+ }
+
+ @Bean(name = "Orders")
+ ClientRegionFactoryBean<Long, Product> ordersRegion(GemFireCache gemfireCache) {
+
+ ClientRegionFactoryBean<Long, Product> orders = new ClientRegionFactoryBean<>();
+
+ orders.setCache(gemfireCache);
+ orders.setClose(true);
+ orders.setShortcut(ClientRegionShortcut.PROXY);
+
+ return orders;
+ }
+
+ @Bean(name = "Products")
+ ClientRegionFactoryBean<Long, Product> productsRegion(GemFireCache gemfireCache) {
+
+ ClientRegionFactoryBean<Long, Product> products = new ClientRegionFactoryBean<>();
+
+ products.setCache(gemfireCache);
+ products.setClose(true);
+ products.setShortcut(ClientRegionShortcut.PROXY);
+
+ return products;
+ }
+
+ @Bean
+ ContinuousQueryListenerContainer continuousQueryListenerContainer(GemFireCache gemfireCache) {
+
+ Region<Long, Customer> customers = gemfireCache.getRegion("/Customers");
+ Region<Long, Product> products = gemfireCache.getRegion("/Products");
+
+ ContinuousQueryListenerContainer container = new ContinuousQueryListenerContainer();
+
+ container.setCache(gemfireCache);
+ container.setQueryListeners(asSet(cheapOrdersQuery(customers, products, 1000),
+ expensiveOrdersQuery(customers, products, 2000)));
+
+ return container;
+ }
+
+ private ContinuousQueryDefinition cheapOrdersQuery(
+ Region<Long, Customer> customers, Region<Long, Product> products, int total) {
+
+ String query = String.format("SELECT * FROM /Orders o WHERE o.getTotal().intValue() < %d", total);
+
+ return new ContinuousQueryDefinition("Cheap Orders", query,
+ newQueryListener(customers, "Cheap"));
+ }
+
+ private ContinuousQueryDefinition expensiveOrdersQuery(
+ Region<Long, Customer> customers, Region<Long, Product> products, int total) {
+
+ String query = String.format("SELECT * FROM /Orders o WHERE o.getTotal().intValue() > %d", total);
+
+ return new ContinuousQueryDefinition("Expensive Orders", query,
+ newQueryListener(customers, "Expensive"));
+ }
+
+ private ContinuousQueryListener newQueryListener(Region<Long, Customer> customers, String qualifier) {
+
+ return event -> {
+
+ Order order = (Order) event.getNewValue();
+
+ System.err.printf("[%s] made an %s Order [%s] for [%s]%n",
+ findByCustomerId(customers, order.getCustomerId()), qualifier, order, order.getLineItems());
+ };
+ }
+
+ private Customer findByCustomerId(Region<Long, Customer> customers, Long customerId) {
+ return customers.get(customerId);
+ }
+}
Oops, something went wrong.

0 comments on commit 2559042

Please sign in to comment.