You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by up...@apache.org on 2017/10/19 22:30:42 UTC

[geode-examples] branch develop updated: GEODE-3691: Add an example of a cache writer. (#19)

This is an automated email from the ASF dual-hosted git repository.

upthewaterspout pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-examples.git


The following commit(s) were added to refs/heads/develop by this push:
     new 5cc2f0e  GEODE-3691: Add an example of a cache writer. (#19)
5cc2f0e is described below

commit 5cc2f0ed77784c87ac70e0c2cc2ca75e212d0f08
Author: Michael "Sarge" Dodge <md...@pivotal.io>
AuthorDate: Thu Oct 19 15:30:41 2017 -0700

    GEODE-3691: Add an example of a cache writer. (#19)
    
    Create a cache writer that rejects invalid SSNs.
---
 README.md                                          |  4 +-
 build.gradle                                       | 14 +++--
 settings.gradle                                    |  1 +
 writer/README.md                                   | 45 ++++++++++++++++
 writer/scripts/start.gfsh                          | 28 ++++++++++
 writer/scripts/stop.gfsh                           | 20 ++++++++
 .../org/apache/geode/examples/writer/Example.java  | 60 ++++++++++++++++++++++
 .../geode/examples/writer/ExampleCacheWriter.java  | 58 +++++++++++++++++++++
 .../apache/geode/examples/writer/SSNVetter.java    | 30 +++++++++++
 .../examples/writer/ExampleCacheWriterTest.java    | 43 ++++++++++++++++
 .../apache/geode/examples/writer/ExampleTest.java  | 43 ++++++++++++++++
 .../geode/examples/writer/SSNVetterTest.java       | 33 ++++++++++++
 12 files changed, 374 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 2b031d5..06e398f 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,9 @@ tutorial.
 *  PDX & Serialization
 *  Lucene Indexing
 *  OQL Indexing
-*  CacheLoader & CacheWriter
+*  Functions
+*  [Cache Loader](loader/README.md)
+*  [Cache Writer](writer/README.md)
 *  Listeners
 *  Async Event Queues
 *  Continuous Querying
diff --git a/build.gradle b/build.gradle
index 61dd2b2..e6844e3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -102,10 +102,16 @@ subprojects {
     archiveName "${baseName}.${extension}"
   }
 
-  task cleanServer << {
-    delete 'locator'
-    delete 'server1'
-    delete 'server2'
+  jar {
+    archiveName "${baseName}.${extension}"
+  }
+  
+  task cleanServer {
+    doLast {
+      delete 'locator'
+      delete 'server1'
+      delete 'server2'
+    }
   }
   clean.finalizedBy cleanServer
 
diff --git a/settings.gradle b/settings.gradle
index 9c78100..5402e65 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -24,3 +24,4 @@ include 'putall'
 include 'clientSecurity'
 include 'functions'
 include 'persistence'
+include 'writer'
diff --git a/writer/README.md b/writer/README.md
new file mode 100644
index 0000000..624c479
--- /dev/null
+++ b/writer/README.md
@@ -0,0 +1,45 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+-->
+
+# Geode Cache Writer Example
+
+This is a simple example that demonstrates the use of a cache writer to validate modifications to a region.
+
+A cache writer is added to a region as the region is created. _Before_ an event (e.g., create a new entry, update an existing entry) occurs on that region, the cache writer has the appropriate handler method invoked, e.g., `beforeCreate()` for creating a new entry. This method invocation _can_ affect the operation on the region: if it throws `CacheWriterException` the operation is aborted.
+
+In this example, a cache writer is installed that vets all of the creation events for the region for proper formatting of Social Security numbers. A number of entries are created in the region. The cache writer vets the supplied key for valid formatting. In other applications, the event could either be persisted to some other data store (i.e., write-ahead) or a notification about the activity could be sent via some other mechanism.
+
+This example assumes you have installed Java and Geode.
+
+## Steps
+
+1. From the `geode-examples/writer` directory, build the example and
+   run unit tests.
+
+        $ ../gradlew build
+
+2. Next start a locator, start a server, and create a region.
+
+        $ gfsh run --file=scripts/start.gfsh
+
+3. Run the example to add a cache listener, put entries into the region, and capture the events.
+
+        $ ../gradlew run
+
+4. Shut down the system.
+
+        $ gfsh run --file=scripts/stop.gfsh
diff --git a/writer/scripts/start.gfsh b/writer/scripts/start.gfsh
new file mode 100644
index 0000000..719d663
--- /dev/null
+++ b/writer/scripts/start.gfsh
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+start locator --name=locator --bind-address=127.0.0.1
+
+start server --name=server1 --locators=127.0.0.1[10334] --server-port=0
+start server --name=server2 --locators=127.0.0.1[10334] --server-port=0
+
+deploy --jar=build/libs/writer.jar
+
+create region --name=example-region --type=REPLICATE --cache-writer=org.apache.geode.examples.writer.ExampleCacheWriter
+
+list members
+describe region --name=example-region
diff --git a/writer/scripts/stop.gfsh b/writer/scripts/stop.gfsh
new file mode 100644
index 0000000..c3bed1d
--- /dev/null
+++ b/writer/scripts/stop.gfsh
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+connect --locator=127.0.0.1[10334]
+destroy region --name=example-region
+shutdown --include-locators=true
diff --git a/writer/src/main/java/org/apache/geode/examples/writer/Example.java b/writer/src/main/java/org/apache/geode/examples/writer/Example.java
new file mode 100644
index 0000000..a33a524
--- /dev/null
+++ b/writer/src/main/java/org/apache/geode/examples/writer/Example.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.examples.writer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.geode.cache.CacheWriterException;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.cache.client.ServerOperationException;
+
+public class Example {
+  public static void main(String[] args) {
+    // connect to the locator using default port 10334
+    ClientCache cache = new ClientCacheFactory().addPoolLocator("127.0.0.1", 10334)
+        .set("log-level", "WARN").create();
+
+    // create a local region that matches the server region
+    Region<String, String> region =
+        cache.<String, String>createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
+            .create("example-region");
+
+    new Example().getValidNames(region);
+    cache.close();
+  }
+
+  private void addName(Region<String, String> region, String ssn, String name, List<String> names) {
+    try {
+      region.put(ssn, name);
+      names.add(name);
+    } catch (CacheWriterException | ServerOperationException e) {
+      System.out.println("Invalid SSN: " + ssn);
+    }
+  }
+
+  public List<String> getValidNames(Region<String, String> region) {
+    List<String> names = new ArrayList<>();
+    addName(region, "123-45-6789", "Bart Simpson", names);
+    addName(region, "666-66-6666", "Bill Gates", names);
+    addName(region, "777-77-7777", "Raymond Babbitt", names);
+    addName(region, "8675309", "Jenny", names);
+    addName(region, "999-000-0000", "Blackberry", names);
+    return names;
+  }
+}
diff --git a/writer/src/main/java/org/apache/geode/examples/writer/ExampleCacheWriter.java b/writer/src/main/java/org/apache/geode/examples/writer/ExampleCacheWriter.java
new file mode 100644
index 0000000..05da018
--- /dev/null
+++ b/writer/src/main/java/org/apache/geode/examples/writer/ExampleCacheWriter.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.examples.writer;
+
+import org.apache.geode.cache.CacheWriter;
+import org.apache.geode.cache.CacheWriterException;
+import org.apache.geode.cache.EntryEvent;
+import org.apache.geode.cache.RegionEvent;
+
+public class ExampleCacheWriter implements CacheWriter<String, String> {
+  final SSNVetter vetter = new SSNVetter();
+
+  @Override
+  public void beforeUpdate(EntryEvent<String, String> event) throws CacheWriterException {
+    if (!vetter.isValid(event.getKey())) {
+      throw new CacheWriterException("Invalid SSN");
+    }
+  }
+
+  @Override
+  public void beforeCreate(EntryEvent<String, String> event) throws CacheWriterException {
+    if (!vetter.isValid(event.getKey())) {
+      throw new CacheWriterException("Invalid SSN");
+    }
+  }
+
+  @Override
+  public void beforeDestroy(EntryEvent<String, String> event) throws CacheWriterException {
+    // N/A
+  }
+
+  @Override
+  public void beforeRegionDestroy(RegionEvent<String, String> event) throws CacheWriterException {
+    // N/A
+  }
+
+  @Override
+  public void beforeRegionClear(RegionEvent<String, String> event) throws CacheWriterException {
+    // N/A
+  }
+
+  @Override
+  public void close() {
+    // N/A
+  }
+}
diff --git a/writer/src/main/java/org/apache/geode/examples/writer/SSNVetter.java b/writer/src/main/java/org/apache/geode/examples/writer/SSNVetter.java
new file mode 100644
index 0000000..4229d17
--- /dev/null
+++ b/writer/src/main/java/org/apache/geode/examples/writer/SSNVetter.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.examples.writer;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SSNVetter {
+  private final Pattern ssnPattern = Pattern.compile("^\\s*([0-8]\\d{2})-?\\d{2}-?\\d{4}\\s*$");
+
+  public boolean isValid(String text) {
+    final Matcher m = ssnPattern.matcher(text);
+    if (m.matches() && !m.group(1).equals("666")) {
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/writer/src/test/java/org/apache/geode/examples/writer/ExampleCacheWriterTest.java b/writer/src/test/java/org/apache/geode/examples/writer/ExampleCacheWriterTest.java
new file mode 100644
index 0000000..e8a13e2
--- /dev/null
+++ b/writer/src/test/java/org/apache/geode/examples/writer/ExampleCacheWriterTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.examples.writer;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+import org.apache.geode.cache.CacheWriterException;
+import org.apache.geode.cache.EntryEvent;
+
+public class ExampleCacheWriterTest {
+  @Test(expected = CacheWriterException.class)
+  public void testBeforeCreateFailsForBadSSN() throws Exception {
+    ExampleCacheWriter writer = new ExampleCacheWriter();
+
+    EntryEvent<String, String> event = mock(EntryEvent.class);
+    when(event.getKey()).thenReturn("666-66-6666");
+    writer.beforeCreate(event);
+  }
+
+  @Test
+  public void testBeforeCreatePassesWithGoodSSN() throws Exception {
+    ExampleCacheWriter writer = new ExampleCacheWriter();
+
+    EntryEvent<String, String> event = mock(EntryEvent.class);
+    when(event.getKey()).thenReturn("555-66-6666");
+    writer.beforeCreate(event);
+  }
+}
diff --git a/writer/src/test/java/org/apache/geode/examples/writer/ExampleTest.java b/writer/src/test/java/org/apache/geode/examples/writer/ExampleTest.java
new file mode 100644
index 0000000..bfa252b
--- /dev/null
+++ b/writer/src/test/java/org/apache/geode/examples/writer/ExampleTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.examples.writer;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import org.apache.geode.cache.CacheWriterException;
+import org.apache.geode.cache.Region;
+
+import org.geode.examples.util.Mocks;
+import org.junit.Test;
+
+public class ExampleTest {
+  @Test
+  public void testExample() throws Exception {
+    Example example = new Example();
+
+    Region<String, String> region = Mocks.region("example-region");
+    when(region.put(eq("666-66-6666"), any())).thenThrow(new CacheWriterException());
+    when(region.put(eq("8675309"), any())).thenThrow(new CacheWriterException());
+    when(region.put(eq("999-000-0000"), any())).thenThrow(new CacheWriterException());
+
+    assertEquals(Arrays.asList(new String[] {"Bart Simpson", "Raymond Babbitt"}),
+        example.getValidNames(region));
+  }
+}
diff --git a/writer/src/test/java/org/apache/geode/examples/writer/SSNVetterTest.java b/writer/src/test/java/org/apache/geode/examples/writer/SSNVetterTest.java
new file mode 100644
index 0000000..34c83fd
--- /dev/null
+++ b/writer/src/test/java/org/apache/geode/examples/writer/SSNVetterTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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.apache.geode.examples.writer;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class SSNVetterTest {
+  @Test
+  public void testIsValid() throws Exception {
+    SSNVetter vetter = new SSNVetter();
+
+    assertTrue(vetter.isValid("123-45-6789"));
+    assertFalse(vetter.isValid("666-66-6666"));
+    assertTrue(vetter.isValid("777-77-7777"));
+    assertFalse(vetter.isValid("8675309"));
+    assertFalse(vetter.isValid("999-000-0000"));
+  }
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@geode.apache.org" <co...@geode.apache.org>'].