Merge branch 'release/1.5.0'
diff --git a/README.md b/README.md
index e77194b..2aad532 100644
--- a/README.md
+++ b/README.md
@@ -26,10 +26,14 @@
 about your suggestions at [dev@geode.apache.org](mailto:dev@geode.apache.org)
 or submit a [pull request](https://github.com/apache/geode/pull/new/develop).
 
+# Apache Geode Version
+
+Check out the master branch to run examples against the latest geode release.
+
 ## Running an example
 
 The gradle build will automatically download and install a Geode release in the
-`build` directory.  You can run an example with the following gradle targets:
+`build` directory. You can run an example with the following gradle targets:
 
 * `build` - compiles the example and runs unit tests
 * `start` - initializes the Geode cluster
@@ -37,18 +41,18 @@
 * `stop` - shuts down the cluster
 * `runAll` - invokes start, run, stop
 
-The commands you need to invoke will be given in the `README.md` file.  Sample
+The commands you need to invoke will be given in the `README.md` file. Sample
 usage:
 
-    $ ./gradle :replicated:start
-    $ ./gradle :replicated:run
-    $ ./gradle :replicated:stop
-    $ ./gradle runAll
+    $ ./gradlew :replicated:start
+    $ ./gradlew :replicated:run
+    $ ./gradlew :replicated:stop
+    $ ./gradlew runAll
 
 ## Catalog of examples
 
 The following sections call out ready-made examples or new examples that could
-be built.  You may want to start your journey with the [Apache Geode in 15
+be built. You may want to start your journey with the [Apache Geode in 15
 minutes or
 Less](http://geode.apache.org/docs/guide/13/getting_started/15_minute_quickstart_gfsh.html)
 tutorial.
@@ -60,22 +64,21 @@
 *  [Put Multiple Values at Once](putall/README.md)
 *  [Functions](functions/README.md)
 *  [Persistence](persistence/README.md)
-*  OQL (Querying)
+*  [OQL (Querying)](queries/README.md)
 
 ### Intermediate
 
-*  PDX & Serialization
-*  Lucene Indexing
-*  OQL Indexing
-*  Functions
+*  [Serialization](serialization/README.md)
+*  [Lucene Indexing](lucene/README.md)
+*  [OQL Indexing](indexes/README.md)
 *  [Cache Loader](loader/README.md)
 *  [Cache Writer](writer/README.md)
 *  [Cache Listeners](listener/README.md)
 *  [Async Event Queues & Async Event Listeners](async/README.md)
 *  Continuous Querying
 *  Transactions
-*  Eviction
-*  Expiration
+*  [Eviction](eviction/README.md)
+*  [Expiration](expiration/README.md)
 *  Overflow
 *  Security
 *  Off-heap
@@ -111,14 +114,17 @@
 * Create a Java class with a main method in the `org.apache.geode_examples.$name.Example` class
 * Create a cluster initialization script in `scripts/start.gfsh`
 * Create a cluster shutdown script in `scripts/stop.gfsh`
+* Modify the top-level `settings.gradle` file to include subproject
+* Modify this `README.md` file to include the new example in the catalog of examples
 
 The scripts should contain `gfsh` commands for starting locators, servers, and
-creating regions--everything that the example program will need to use.  Where
-appropriate you should also add unit tests.  To customize the build you can add
+creating regions--everything that the example program will need to use. Where
+appropriate you should also add unit tests. To customize the build you can add
 a `build.gradle` file.
 
+Verify that the examples build by executing `./gradlew runAll` from the root directory.
 Note that the build may fail if you do not add ASF license headers or use the
-correct formatting (you can fix formatting with `gradle spotlessApply`).
+correct formatting. You can fix formatting with `./gradlew spotlessApply`.
 
 ## References
 
diff --git a/build.gradle b/build.gradle
index b88ae07..d748a98 100644
--- a/build.gradle
+++ b/build.gradle
@@ -99,9 +99,51 @@
     main = "org.apache.geode_examples.${project.name}.Example"
   }
 
-  task runAll(dependsOn: [start, run, stop])
+  task waitForExitingMembers(type: Exec) {
+    workingDir projectDir
+    environment 'GEODE_HOME', installDir
+    environment 'PATH', geodePath
+    ignoreExitValue true
+    commandLine 'sh', '-c', "" +
+            "TIMEOUT=10 ;" +
+            "echo \"Waiting at most \$TIMEOUT seconds for all members to shut down...\" ;" +
+            "while pgrep -f \"(Server|Locator)Launcher\" > /dev/null ; do  printf \".\" ; " +
+            "  sleep 1 ;" +
+            "  TIMEOUT=\$((\$TIMEOUT - 1)) ;" +
+            "  if [[ \$TIMEOUT -eq 0 ]] ; then" +
+            "    echo \"\" ;" +
+            "    exit 10 ;" +
+            "  fi ;" +
+            "done ;" +
+            "echo \"\""
+    doLast {
+      // We use exit code 10 to avoid conflict with pgrep exit codes.
+      if (execResult.exitValue == 10) {
+        throw new GradleException("A member process persisted beyond permitted timeout.  Aborting.")
+      } else if (execResult.exitValue != 0) {
+        throw new GradleException("waitForExistingMembers failed with exit code: " + execResult.exitValue)
+      }
+    }
+  }
+
+  task verifyNoMembersRunning(type: Exec) {
+    workingDir projectDir
+    environment 'GEODE_HOME', installDir
+    environment 'PATH', geodePath
+    ignoreExitValue true
+    commandLine 'sh', '-c', "pgrep -f \"(Server|Locator)Launcher\" > /dev/null ; "
+    doLast {
+      if (execResult.exitValue == 0) {
+        throw new GradleException("Existing members detected.  Examples expect a clean environment in which to run.")
+      }
+    }
+  }
+
+  task runAll(dependsOn: [verifyNoMembersRunning, start, run, stop, waitForExitingMembers])
+  start.mustRunAfter verifyNoMembersRunning
   run.mustRunAfter start
   stop.mustRunAfter run
+  waitForExitingMembers.mustRunAfter stop
 }
 
 apply from: "gradle/spotless.gradle"
diff --git a/clientSecurity/README.md b/clientSecurity/README.md
index 8626c3d..ff03b9a 100644
--- a/clientSecurity/README.md
+++ b/clientSecurity/README.md
@@ -18,7 +18,8 @@
 # Geode security example - Client
 
 This example demonstrates basic command security and user authentication in a client application
-backed by a secured Geode cluster.  This example assumes that Java and Geode are installed.
+backed by a secured Geode cluster. It also demonstrates use of secure sockets (SSL) between all
+members and between a client and a server.  This example assumes that Java is installed.
 
 ## Security Basics
 
diff --git a/clientSecurity/example_security.properties b/clientSecurity/example_security.properties
index d661639..53e3c44 100644
--- a/clientSecurity/example_security.properties
+++ b/clientSecurity/example_security.properties
@@ -13,3 +13,9 @@
 
 security-manager = org.apache.geode.examples.security.ExampleSecurityManager
 security-json = example_security.json
+
+ssl-enabled-components=all
+ssl-keystore=./../keystore.jks
+ssl-keystore-password=password
+ssl-truststore=./../truststore.jks
+ssl-truststore-password=password
\ No newline at end of file
diff --git a/clientSecurity/keystore.jks b/clientSecurity/keystore.jks
new file mode 100644
index 0000000..6b6e713
--- /dev/null
+++ b/clientSecurity/keystore.jks
Binary files differ
diff --git a/clientSecurity/scripts/start.gfsh b/clientSecurity/scripts/start.gfsh
index 313d035..080d5b4 100644
--- a/clientSecurity/scripts/start.gfsh
+++ b/clientSecurity/scripts/start.gfsh
@@ -20,7 +20,7 @@
 # This requires that the example_security.json be on the classpath.
 # Recall that the --classpath option is specified relative to the locator's working directory.
 
-start locator --name=locator --bind-address=127.0.0.1\
+start locator --name=locator --bind-address=127.0.0.1 --connect=false\
  --security-properties-file=example_security.properties --classpath=../build/resources/main/
 
 # Now we may start our cluster.
@@ -41,6 +41,9 @@
 # To execute any online commands, we need to connect to the locator
 # To create a region, we can connect as any user with CLUSTER:MANAGE
 
-connect --user=superUser --password=123
+connect --user=superUser --password=123 --use-ssl=true \
+  --key-store=keystore.jks --key-store-password=password \
+  --trust-store=truststore.jks --trust-store-password=password
+
 create region --name=region1 --type=REPLICATE
 create region --name=region2 --type=PARTITION
diff --git a/clientSecurity/scripts/stop.gfsh b/clientSecurity/scripts/stop.gfsh
index ad068e3..6f83ea8 100644
--- a/clientSecurity/scripts/stop.gfsh
+++ b/clientSecurity/scripts/stop.gfsh
@@ -14,5 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-connect --locator=127.0.0.1[10334] --user=superUser --password=123
+connect --locator=127.0.0.1[10334] --user=superUser --password=123 --use-ssl=true \
+   --key-store=./keystore.jks --key-store-password=password \
+   --trust-store=./truststore.jks --trust-store-password=password
 shutdown --include-locators=true
diff --git a/clientSecurity/src/main/java/org/apache/geode_examples/clientSecurity/Example.java b/clientSecurity/src/main/java/org/apache/geode_examples/clientSecurity/Example.java
index cb72786..f6762af 100644
--- a/clientSecurity/src/main/java/org/apache/geode_examples/clientSecurity/Example.java
+++ b/clientSecurity/src/main/java/org/apache/geode_examples/clientSecurity/Example.java
@@ -59,6 +59,11 @@
     Properties props = new Properties();
     props.setProperty("security-username", username);
     props.setProperty("security-client-auth-init", ExampleAuthInit.class.getName());
+    props.setProperty("ssl-enabled-components", "all");
+    props.setProperty("ssl-keystore", "keystore.jks");
+    props.setProperty("ssl-keystore-password", "password");
+    props.setProperty("ssl-truststore", "truststore.jks");
+    props.setProperty("ssl-truststore-password", "password");
 
     // connect to the locator using default port 10334
     cache = new ClientCacheFactory(props).setPoolSubscriptionEnabled(true)
diff --git a/clientSecurity/truststore.jks b/clientSecurity/truststore.jks
new file mode 100644
index 0000000..6b6e713
--- /dev/null
+++ b/clientSecurity/truststore.jks
Binary files differ
diff --git a/eviction/README.md b/eviction/README.md
new file mode 100644
index 0000000..239a944
--- /dev/null
+++ b/eviction/README.md
@@ -0,0 +1,53 @@
+<!--
+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 Eviction Example
+
+This is a simple example that demonstrates eviction of entries from a region. This allows control
+over the system resources consumed by any given region.
+
+A region is a collection of entries which are tuples of key and value. Each entry requires memory
+for the key object, the value object, and some overhead. Regions that contain a large number of
+entries, entries of a large size, or both can consume enough system resources to impact overall
+system performance, even for other regions.
+
+A region can have eviction enabled to enforce an upper limit on either the total number of entries
+_or_ the total amount of memory consumed by the entries. The region will then enforce the specified
+limits on its in-memory resource consumption. When an operation would exceed those limits, the
+region will take an action to assure that the limits will not be exceeded after the operation
+completes. The region can either destroy one or more entries or overflow one or more entries to disk.
+
+This example assumes you have installed Java and Geode.
+
+## Steps
+
+1. From the `geode-examples/eviction` 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 demonstrate eviction.
+
+        $ ../gradlew run
+
+4. Shut down the system.
+
+        $ gfsh run --file=scripts/stop.gfsh
diff --git a/eviction/scripts/start.gfsh b/eviction/scripts/start.gfsh
new file mode 100755
index 0000000..163aae9
--- /dev/null
+++ b/eviction/scripts/start.gfsh
@@ -0,0 +1,25 @@
+#
+# 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 --classpath=../build/classes/main
+start server --name=server2 --locators=127.0.0.1[10334] --server-port=0 --classpath=../build/classes/main
+list members
+
+create region --name=example-region --type=REPLICATE --skip-if-exists=true \
+    --eviction-entry-count=10 --eviction-action=local-destroy
+describe region --name=example-region
diff --git a/eviction/scripts/stop.gfsh b/eviction/scripts/stop.gfsh
new file mode 100755
index 0000000..15cd93c
--- /dev/null
+++ b/eviction/scripts/stop.gfsh
@@ -0,0 +1,19 @@
+#
+# 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]
+shutdown --include-locators=true
diff --git a/eviction/src/main/java/org/apache/geode_examples/eviction/Example.java b/eviction/src/main/java/org/apache/geode_examples/eviction/Example.java
new file mode 100644
index 0000000..b83dfbb
--- /dev/null
+++ b/eviction/src/main/java/org/apache/geode_examples/eviction/Example.java
@@ -0,0 +1,72 @@
+/*
+ * 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.eviction;
+
+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.ClientRegionFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+public class Example {
+  public static final int ITERATIONS = 20;
+
+  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();
+
+    Example example = new Example();
+
+    // create a local region that matches the server region
+    ClientRegionFactory<Integer, String> clientRegionFactory =
+        cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
+    Region<Integer, String> region = clientRegionFactory.create("example-region");
+
+    example.putEntries(region);
+    cache.close();
+  }
+
+  private Collection<Integer> generateIntegers() {
+    IntStream stream = new Random().ints(0, ITERATIONS);
+    Iterator<Integer> iterator = stream.iterator();
+    Set<Integer> integers = new LinkedHashSet<>();
+    while (iterator.hasNext() && integers.size() < ITERATIONS) {
+      integers.add(iterator.next());
+    }
+    return integers;
+  }
+
+  public void putEntries(Region<Integer, String> region) {
+    Collection<Integer> integers = generateIntegers();
+    Iterator<Integer> iterator = integers.iterator();
+
+    int created = 0;
+    while (iterator.hasNext()) {
+      Integer integer = iterator.next();
+      region.put(integer, integer.toString());
+      System.out.println("Added value for " + integer + "; the region now has "
+          + region.sizeOnServer() + " entries.");
+      ++created;
+    }
+  }
+}
diff --git a/expiration/README.md b/expiration/README.md
new file mode 100644
index 0000000..74edb95
--- /dev/null
+++ b/expiration/README.md
@@ -0,0 +1,54 @@
+<!--
+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 Expiration Example
+
+This is a simple example that demonstrates expiration of entries from a region. This can be used to
+prevent stale entries from lingering in a region. This also allows control over the system resources
+consumed by any given region.
+
+A region is a collection of entries which are tuples of key and value. When statistics-gathering is
+enabled, the region maintains access and modification times for each entry. With entry expiration
+configured, the region will enforce time-to-live limits on entries. When the time since access or
+modification exceeds the configured duration, the region will take an action to expire the entry.
+The region can either destroy expired entries in their entirety or invalidate expired entries by
+removing their values.
+
+This example creates a region where the entries are destroyed after ten seconds without being
+updated. The example first puts ten random integers into the region. Then the example loops,
+printing the number of entries in the region, until the region is empty.
+
+This example assumes you have installed Java and Geode.
+
+## Steps
+
+1. From the `geode-examples/expiration` 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 demonstrate expiration.
+
+        $ ../gradlew run
+
+4. Shut down the system.
+
+        $ gfsh run --file=scripts/stop.gfsh
diff --git a/expiration/scripts/start.gfsh b/expiration/scripts/start.gfsh
new file mode 100755
index 0000000..e06d1d2
--- /dev/null
+++ b/expiration/scripts/start.gfsh
@@ -0,0 +1,26 @@
+#
+# 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 --classpath=../build/classes/main
+start server --name=server2 --locators=127.0.0.1[10334] --server-port=0 --classpath=../build/classes/main
+list members
+
+create region --name=example-region --type=REPLICATE --skip-if-exists=true \
+    --enable-statistics=true \
+    --entry-time-to-live-expiration=10 --entry-time-to-live-expiration-action=local-destroy
+describe region --name=example-region
diff --git a/expiration/scripts/stop.gfsh b/expiration/scripts/stop.gfsh
new file mode 100755
index 0000000..15cd93c
--- /dev/null
+++ b/expiration/scripts/stop.gfsh
@@ -0,0 +1,19 @@
+#
+# 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]
+shutdown --include-locators=true
diff --git a/expiration/src/main/java/org/apache/geode_examples/expiration/Example.java b/expiration/src/main/java/org/apache/geode_examples/expiration/Example.java
new file mode 100644
index 0000000..c13758b
--- /dev/null
+++ b/expiration/src/main/java/org/apache/geode_examples/expiration/Example.java
@@ -0,0 +1,88 @@
+/*
+ * 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.expiration;
+
+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.ClientRegionFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+public class Example {
+  private static final DateFormat ISO_8601_TIMESTAMP_FORMAT =
+      new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
+
+  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();
+
+    Example example = new Example();
+
+    // create a local region that matches the server region
+    ClientRegionFactory<Integer, String> clientRegionFactory =
+        cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
+    Region<Integer, String> region = clientRegionFactory.create("example-region");
+
+    example.insertValues(region, example.generateIntegers(10));
+    example.monitorEntries(region);
+
+    cache.close();
+  }
+
+  private Collection<Integer> generateIntegers(int upperLimit) {
+    IntStream stream = new Random().ints(0, upperLimit);
+    Iterator<Integer> iterator = stream.iterator();
+    Set<Integer> integers = new LinkedHashSet<>();
+    while (iterator.hasNext() && integers.size() < upperLimit) {
+      integers.add(iterator.next());
+    }
+    return integers;
+  }
+
+  void insertValues(Region<Integer, String> region, Collection<Integer> integers) {
+    Map values = new HashMap<Integer, String>();
+    for (Integer i : integers) {
+      values.put(i, i.toString());
+    }
+    region.putAll(values);
+    System.out.println(
+        ISO_8601_TIMESTAMP_FORMAT.format(new Date()) + "\tInserted " + values.size() + " values.");
+  }
+
+  public void monitorEntries(Region<Integer, String> region) {
+    while (0 < region.sizeOnServer()) {
+      try {
+        Thread.sleep(1000);
+        System.out.println(ISO_8601_TIMESTAMP_FORMAT.format(new Date()) + "\tThe region now has "
+            + region.sizeOnServer() + " entries.");
+      } catch (InterruptedException ie) {
+        // NOP
+      }
+    }
+  }
+}
diff --git a/gradle.properties b/gradle.properties
index 62ed75d..054dabb 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,8 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-version = 1.4.0
-geodeVersion = 1.4.0
+version = 1.5.0
+geodeVersion = 1.5.0
 
 # release properties, set these on the command line to validate against
 # a release candidate
diff --git a/indexes/README.md b/indexes/README.md
new file mode 100644
index 0000000..b8ed7a7
--- /dev/null
+++ b/indexes/README.md
@@ -0,0 +1,57 @@
+<!--
+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 OQL Indexing Example
+
+This example demonstrates an index for OQL
+[queries](https://geode.apache.org/docs/guide/11/developing/query_index/query_index.html)
+on a region.
+
+A region can contain objects of arbitrary complexity, including objects that contain other objects.
+The values of a region can be queried using
+[OQL](https://geode.apache.org/docs/guide/11/developing/querying_basics/chapter_overview.html) and
+OQL queries can reference fields in the objects in the region. Indexes can be created to improve
+the performance of queries. Certain optimizations occur for top-level fields but indexes can also be
+created for nested fields, i.e., fields of objects that are contained with the objects in the
+region.
+
+This example uses a mock database of passengers and flights stored in a single region. Since the
+region contains passenger objects, the index on passenger name uses a top-level field.
+Since flight code objects are contained within a passenger object, the index on airline code uses a
+nested field. After randomly populating the mock database, this example shows the results of queries
+that use no index, a top-level index, and a nested index.
+
+This example assumes that Java and Geode are installed.
+
+## Steps
+
+1. From the `geode-examples/indexes` directory, build the example and
+   run unit tests.
+
+        $ ../gradlew build
+
+2. Next start the locator and two servers.
+
+        $ gfsh run --file=scripts/start.gfsh
+
+3. Run the example to create indexes in the region.
+
+        $ ../gradlew run
+
+4. Shut down the system.
+
+        $ gfsh run --file=scripts/stop.gfsh
diff --git a/indexes/scripts/start.gfsh b/indexes/scripts/start.gfsh
new file mode 100644
index 0000000..1a2e3ae
--- /dev/null
+++ b/indexes/scripts/start.gfsh
@@ -0,0 +1,26 @@
+#
+# 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 --classpath=../build/classes/main
+start server --name=server2 --locators=127.0.0.1[10334] --server-port=0 --classpath=../build/classes/main
+list members
+
+create region --name=example-region --type=REPLICATE --skip-if-exists=true
+create index --name=topLevelIndex --expression=name --region=/example-region
+create index --name=nestedIndex --expression=flight.airlineCode --region=/example-region
+describe region --name=example-region
diff --git a/indexes/scripts/stop.gfsh b/indexes/scripts/stop.gfsh
new file mode 100644
index 0000000..15cd93c
--- /dev/null
+++ b/indexes/scripts/stop.gfsh
@@ -0,0 +1,19 @@
+#
+# 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]
+shutdown --include-locators=true
diff --git a/indexes/src/main/java/org/apache/geode_examples/indexes/Example.java b/indexes/src/main/java/org/apache/geode_examples/indexes/Example.java
new file mode 100644
index 0000000..5f14964
--- /dev/null
+++ b/indexes/src/main/java/org/apache/geode_examples/indexes/Example.java
@@ -0,0 +1,82 @@
+/*
+ * 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.indexes;
+
+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.ClientRegionFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.cache.query.FunctionDomainException;
+import org.apache.geode.cache.query.NameResolutionException;
+import org.apache.geode.cache.query.QueryInvocationTargetException;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.TypeMismatchException;
+
+public class Example {
+  static String REGIONNAME = "example-region";
+  static String NON_INDEXED_QUERY = "SELECT DISTINCT * FROM /" + REGIONNAME;
+  static String TOP_LEVEL_INDEX_QUERY =
+      "SELECT DISTINCT * FROM /" + REGIONNAME + " p WHERE p.name LIKE $1";
+  static String NESTED_INDEX_QUERY =
+      "SELECT DISTINCT * FROM /" + REGIONNAME + " p WHERE p.flight.airlineCode=$1";
+
+  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();
+
+    Example example = new Example();
+
+    // create a local region that matches the server region
+    ClientRegionFactory<String, Passenger> clientRegionFactory =
+        cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
+    Region<String, Passenger> region = clientRegionFactory.create("example-region");
+    QueryService queryService = cache.getQueryService();
+
+    RegionPopulator populator = new RegionPopulator();
+    populator.populateRegion(region);
+
+    System.out.println("Total number of passengers: "
+        + example.countResults(queryService, NON_INDEXED_QUERY, new Object[] {}));
+    for (String lastName : populator.lastNames) {
+      System.out.println("Flights for " + lastName + ": " + example.countResults(queryService,
+          TOP_LEVEL_INDEX_QUERY, new Object[] {"%" + lastName}));
+    }
+    for (String airline : populator.airlines) {
+      System.out.println("Flights for " + airline + ": "
+          + example.countResults(queryService, NESTED_INDEX_QUERY, new Object[] {airline}));
+    }
+
+    cache.close();
+  }
+
+  int countResults(QueryService queryService, String queryString, Object[] params) {
+    try {
+      int count = 0;
+      SelectResults<Passenger> results =
+          (SelectResults<Passenger>) queryService.newQuery(queryString).execute(params);
+      for (Passenger passenger : results) {
+        ++count;
+      }
+      return count;
+    } catch (FunctionDomainException | TypeMismatchException | NameResolutionException
+        | QueryInvocationTargetException e) {
+      e.printStackTrace();
+      return -1;
+    }
+  }
+}
diff --git a/indexes/src/main/java/org/apache/geode_examples/indexes/FlightCode.java b/indexes/src/main/java/org/apache/geode_examples/indexes/FlightCode.java
new file mode 100644
index 0000000..1a4d7fa
--- /dev/null
+++ b/indexes/src/main/java/org/apache/geode_examples/indexes/FlightCode.java
@@ -0,0 +1,54 @@
+/*
+ * 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.indexes;
+
+import java.io.Serializable;
+
+public class FlightCode implements Serializable {
+  private static final long serialVersionUID = -4252046061229265115L;
+
+  String airlineCode;
+  int flightNumber;
+  String departure;
+  String arrival;
+
+  public FlightCode(String airlineCode, int flightNumber, String departure, String arrival) {
+    this.airlineCode = airlineCode;
+    this.flightNumber = flightNumber;
+    this.departure = departure;
+    this.arrival = arrival;
+  }
+
+  public String getAirlineCode() {
+    return airlineCode;
+  }
+
+  public int getFlightNumber() {
+    return flightNumber;
+  }
+
+  public String getDeparture() {
+    return departure;
+  }
+
+  public String getArrival() {
+    return arrival;
+  }
+
+  public String toString() {
+    return getAirlineCode() + String.format("%03d", getFlightNumber()) + " from " + getDeparture()
+        + " to " + getArrival();
+  }
+}
diff --git a/indexes/src/main/java/org/apache/geode_examples/indexes/Passenger.java b/indexes/src/main/java/org/apache/geode_examples/indexes/Passenger.java
new file mode 100644
index 0000000..aabfc06
--- /dev/null
+++ b/indexes/src/main/java/org/apache/geode_examples/indexes/Passenger.java
@@ -0,0 +1,66 @@
+/*
+ * 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.indexes;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class Passenger implements Serializable {
+  private static final long serialVersionUID = -991115968572408216L;
+  static final DateFormat ISO_8601_TIMESTAMP_FORMAT =
+      new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
+
+  String name;
+  int age;
+  FlightCode flight;
+  Date departure;
+  Date arrival;
+
+  public Passenger(String name, int age, FlightCode flight, Date departure, Date arrival) {
+    this.name = name;
+    this.age = age;
+    this.flight = flight;
+    this.departure = departure;
+    this.arrival = arrival;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public int getAge() {
+    return age;
+  }
+
+  public FlightCode getFlight() {
+    return flight;
+  }
+
+  public Date getDeparture() {
+    return departure;
+  }
+
+  public Date getArrival() {
+    return arrival;
+  }
+
+  public String toString() {
+    return getName() + ", age " + getAge() + ", flight " + getFlight() + ", departing at "
+        + ISO_8601_TIMESTAMP_FORMAT.format(getDeparture()) + ", arriving at "
+        + ISO_8601_TIMESTAMP_FORMAT.format(getArrival());
+  }
+}
diff --git a/indexes/src/main/java/org/apache/geode_examples/indexes/RegionPopulator.java b/indexes/src/main/java/org/apache/geode_examples/indexes/RegionPopulator.java
new file mode 100644
index 0000000..bc2edea
--- /dev/null
+++ b/indexes/src/main/java/org/apache/geode_examples/indexes/RegionPopulator.java
@@ -0,0 +1,76 @@
+/*
+ * 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.indexes;
+
+import org.apache.geode.cache.Region;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.PrimitiveIterator;
+import java.util.Random;
+
+public class RegionPopulator {
+  static final String[] airlines = "FFT,NKS,ASQ,AAL,UAL,SKW,SWA,HAL,JBU,VRD,DAL,ASA,EIA".split(",");
+  static final String[] cities =
+      "Arendelle City,Szohôd,Portland,Elbonia City,Florin City,Edelweiss,Doomstadt,Markovburg,Parador City,Rio Lindo"
+          .split(",");
+  static final String[] firstNames =
+      "Ava,Brooklyn,Charlotte,Delilah,Emma,Faith,Grace,Harper,Isabella,Julia,Kaylee,Lillian,Mia,Natalie,Olivia,Peyton,Quinn,Riley,Sophia,Taylor,Unique,Victoria,Willow,Ximena,Yaretzi,Zoey"
+          .split(",");
+  static final String[] lastNames =
+      "Smith,Johnson,Williams,Brown,Jones,Miller,Davis,Garcia,Rodriguez,Wilson,Martinez,Anderson,Taylor,Thomas,Hernandez,Moore,Martin,Jackson,Thompson,White,Lopez,Lee,Gonzalez,Harris,Clark,Lewis"
+          .split(",");
+  final Random random = new Random();
+  final LinkedList<FlightCode> flights = new LinkedList<>();
+
+  void populateRegion(Region<String, Passenger> region) {
+    populateFlights(50);
+    insertPassengers(250, region);
+  }
+
+  void populateFlights(int numberOfFlights) {
+    PrimitiveIterator.OfInt flightNumbers = random.ints(1, 1000).iterator();
+    PrimitiveIterator.OfInt airlineIndexes = random.ints(0, airlines.length).iterator();
+    PrimitiveIterator.OfInt cityIndexes = random.ints(0, cities.length).iterator();
+    while (flights.size() < numberOfFlights) {
+      String departure = cities[cityIndexes.next()];
+      String arrival = cities[cityIndexes.next()];
+      while (departure.equals(arrival)) {
+        arrival = cities[cityIndexes.next()];
+      }
+      FlightCode flight =
+          new FlightCode(airlines[airlineIndexes.next()], flightNumbers.next(), departure, arrival);
+      flights.add(flight);
+    }
+  }
+
+  void insertPassengers(int numberOfPassengers, Region<String, Passenger> region) {
+    PrimitiveIterator.OfInt firstNameIndexes = random.ints(0, firstNames.length).iterator();
+    PrimitiveIterator.OfInt lastNameIndexes = random.ints(0, lastNames.length).iterator();
+    PrimitiveIterator.OfInt ages = random.ints(20, 100).iterator();
+    PrimitiveIterator.OfInt flightIndexes = random.ints(0, flights.size()).iterator();
+    PrimitiveIterator.OfInt milliSeconds = random.ints(0, 7 * 24 * 60 * 60 * 1000).iterator();
+    while (region.sizeOnServer() < numberOfPassengers) {
+      String name = firstNames[firstNameIndexes.next()] + " " + lastNames[lastNameIndexes.next()];
+      if (!region.containsKey(name)) {
+        final long departure = System.currentTimeMillis() + milliSeconds.next();
+        final long arrival = departure + milliSeconds.next();
+        Passenger passenger = new Passenger(name, ages.next(), flights.get(flightIndexes.next()),
+            new Date(departure), new Date(arrival));
+        region.put(passenger.getName(), passenger);
+      }
+    }
+  }
+}
diff --git a/serialization/README.md b/serialization/README.md
new file mode 100644
index 0000000..3544edd
--- /dev/null
+++ b/serialization/README.md
@@ -0,0 +1,61 @@
+<!--
+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 serialization example
+
+This is a simple example that demonstrates auto-serialization of objects of classes that do *not*
+use Java serialization, PDX serialization, or data serialization. Reflection-based auto-serialization
+uses Java reflection to put objects into and get objects out of regions without relying on Java,
+PDX, or data serialization.
+
+For an object to be stored in a region as either key or value, a copy of the object must be sent to
+the server. Typically Java objects are sent across the network by serializing them into bytes
+sent across a socket and then deserializing them from the bytes received from the socket on the
+other side. This requires those objects' classes to implement a particular interface that defines
+how that serialization and deserialization is accomplished, e.g., `java.io.Serializable`,
+`org.apache.geode.DataSerializable`, or `org.apache.geode.pdx.PdxSerializable`.
+
+In order to perform queries on objects within the server, the fields of the objects must be
+individually accessible. One way to accomplish this is to deserialize the objects into instances
+within the server. This requires the relevant classes to be in the server's class path. Another way
+to accomplish this is by using the field-addressable format, PDX.
+
+The reflection-based auto-serializer uses Java's reflection and introspection to construct a PDX
+instance. This obviates modifying classes to implement a serialization interface. This also allows
+the objects to be queried by way of PDX without the classes being preset on the server's class
+path.
+
+This example assumes you have installed Java and Geode.
+
+## Steps
+
+1. From the `geode-examples/serialization` directory, build the example and
+   run unit tests
+
+        $ ../gradlew build
+
+2. Next start the locator and two servers
+
+        $ gfsh run --file=scripts/start.gfsh
+
+3. Run the example to create entries in the region
+
+        $ ../gradlew run
+
+4. Shut down the system:
+
+        $ gfsh run --file=scripts/stop.gfsh
diff --git a/serialization/scripts/start.gfsh b/serialization/scripts/start.gfsh
new file mode 100644
index 0000000..1b3af1f
--- /dev/null
+++ b/serialization/scripts/start.gfsh
@@ -0,0 +1,24 @@
+#
+# 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
+list members
+
+create region --name=example-region --type=REPLICATE --skip-if-exists=true
+describe region --name=example-region
diff --git a/serialization/scripts/stop.gfsh b/serialization/scripts/stop.gfsh
new file mode 100644
index 0000000..5dd4874
--- /dev/null
+++ b/serialization/scripts/stop.gfsh
@@ -0,0 +1,19 @@
+#
+# 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]
+
+shutdown --include-locators=true
\ No newline at end of file
diff --git a/serialization/src/main/java/org/apache/geode_examples/serialization/Country.java b/serialization/src/main/java/org/apache/geode_examples/serialization/Country.java
new file mode 100644
index 0000000..39b8e8a
--- /dev/null
+++ b/serialization/src/main/java/org/apache/geode_examples/serialization/Country.java
@@ -0,0 +1,118 @@
+/*
+ * 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.serialization;
+
+/**
+ * <strong>Explicitly</strong> not serializable by java.io.Serializable,
+ * org.apache.geode.DataSerializable, or org.apache.geode.pdx.PdxSerializable.
+ */
+public class Country {
+  protected String name;
+  protected String capitol;
+  protected String language;
+  protected String currency;
+  protected int population;
+
+  public Country() {
+    this("", "", "", "", 0);
+  }
+
+  protected Country(String name, String capitol, String language, String currency, int population) {
+    this.name = name;
+    this.capitol = capitol;
+    this.language = language;
+    this.currency = currency;
+    this.population = population;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getCapitol() {
+    return capitol;
+  }
+
+  public void setCapitol(String capitol) {
+    this.capitol = capitol;
+  }
+
+  public String getLanguage() {
+    return language;
+  }
+
+  public void setLanguage(String language) {
+    this.language = language;
+  }
+
+  public String getCurrency() {
+    return currency;
+  }
+
+  public void setCurrency(String currency) {
+    this.currency = currency;
+  }
+
+  public int getPopulation() {
+    return population;
+  }
+
+  public void setPopulation(int population) {
+    this.population = population;
+  }
+
+  public String toString() {
+    StringBuilder builder = new StringBuilder();
+    if (name != null && !name.isEmpty()) {
+      builder.append(name);
+      builder.append(" (");
+
+      if (capitol != null && !capitol.isEmpty()) {
+        if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+          builder.append(", ");
+        }
+        builder.append("Capitol: ");
+        builder.append(capitol);
+      }
+
+      if (language != null && !language.isEmpty()) {
+        if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+          builder.append(", ");
+        }
+        builder.append("Language: ");
+        builder.append(language);
+      }
+
+      if (currency != null && !currency.isEmpty()) {
+        if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+          builder.append(", ");
+        }
+        builder.append("Currency: ");
+        builder.append(currency);
+      }
+
+      if (0 < population) {
+        if (0 < builder.length() && '(' != builder.charAt(builder.length() - 1)) {
+          builder.append(", ");
+        }
+        builder.append("Population: ");
+        builder.append(population);
+      }
+
+      builder.append(")");
+    }
+    return builder.toString();
+  }
+}
diff --git a/serialization/src/main/java/org/apache/geode_examples/serialization/Example.java b/serialization/src/main/java/org/apache/geode_examples/serialization/Example.java
new file mode 100644
index 0000000..7c4e27e
--- /dev/null
+++ b/serialization/src/main/java/org/apache/geode_examples/serialization/Example.java
@@ -0,0 +1,107 @@
+/*
+ * 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.serialization;
+
+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.pdx.ReflectionBasedAutoSerializer;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class Example {
+  public static final String ARENDELLE = "Arendelle";
+  public static final String BORDURIA = "Borduria";
+  public static final String CASCADIA = "Cascadia";
+  public static final String ELBONIA = "Elbonia";
+  public static final String FLORIN = "Florin";
+  public static final String GRAUSTARK = "Graustark";
+  public static final String LATVERIA = "Latveria";
+  public static final String MARKOVIA = "Markovia";
+  public static final String PARADOR = "Parador";
+  public static final String SIERRA_GORDO = "Sierra Gordo";
+  final Region<String, Country> region;
+
+  public Example(Region<String, Country> region) {
+    this.region = region;
+  }
+
+  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")
+        .setPdxSerializer(
+            new ReflectionBasedAutoSerializer("org.apache.geode_examples.serialization.Country"))
+        .create();
+
+    // create a local region that matches the server region
+    Region<String, Country> region =
+        cache.<String, Country>createClientRegionFactory(ClientRegionShortcut.PROXY)
+            .create("example-region");
+
+    Example example = new Example(region);
+    example.insertValues();
+    example.printValues(example.getKeys());
+
+    cache.close();
+  }
+
+  Country create(String name) {
+    return create(name, name + " City");
+  }
+
+  Country create(String name, String capitol) {
+    return create(name, capitol, "");
+  }
+
+  Country create(String name, String capitol, String language) {
+    return create(name, capitol, language, "", 0);
+  }
+
+  Country create(String name, String capitol, String language, String currency, int population) {
+    return new Country(name, capitol, language, currency, population);
+  }
+
+  Set<String> getKeys() {
+    return new HashSet<>(region.keySetOnServer());
+  }
+
+  void insertValues() {
+    insertValue(create(ARENDELLE, "Arendelle City", "Arendellii", "Arendelle Krona", 76573));
+    insertValue(create(BORDURIA, "Szohôd", "Bordurian", "Bordurian Dinar", 1000000));
+    insertValue(create(CASCADIA, "Portland", "Pacific Northwest English", "United States Dollar",
+        16029520));
+    insertValue(create(ELBONIA));
+    insertValue(create(FLORIN));
+    insertValue(create(GRAUSTARK, "Edelweiss"));
+    insertValue(create(LATVERIA, "Doomstadt", "Latverian", "Latverian Franc", 500000));
+    insertValue(create(MARKOVIA, "Markovburg", "German"));
+    insertValue(create(PARADOR));
+    insertValue(create(SIERRA_GORDO, "Rio Lindo", "Spanish"));
+  }
+
+  void insertValue(Country country) {
+    region.put(country.getName(), country);
+  }
+
+  void printValues(Set<String> keys) {
+    for (String key : keys) {
+      Country country = region.get(key);
+      System.out.println(key + ": " + country);
+    }
+  }
+}
diff --git a/settings.gradle b/settings.gradle
index e43f7f8..d23bb7e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -29,3 +29,7 @@
 include 'listener'
 include 'async'
 include 'luceneSpatial'
+include 'eviction'
+include 'serialization'
+include 'expiration'
+include 'indexes'