You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ra...@apache.org on 2017/05/02 22:32:47 UTC

[1/9] curator git commit: [CURATOR-386] Allow listener to be passed in to PersistentNode

Repository: curator
Updated Branches:
  refs/heads/CURATOR-397 ef9df2b79 -> 1fcb63a5c


[CURATOR-386] Allow listener to be passed in to PersistentNode

This provides ability to hook into events from PersistentNode when a
node gets created.


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/bec1443c
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/bec1443c
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/bec1443c

Branch: refs/heads/CURATOR-397
Commit: bec1443c9cb04f512df8145fbbaaca7c1c6511b4
Parents: 2672049
Author: Alex Kira <ak...@uber.com>
Authored: Fri Feb 10 13:52:59 2017 -0800
Committer: Alex Kira <ak...@uber.com>
Committed: Mon Mar 20 10:13:20 2017 -0700

----------------------------------------------------------------------
 .../framework/recipes/nodes/PersistentNode.java | 42 +++++++++++++++++++-
 .../recipes/nodes/PersistentNodeListener.java   | 33 +++++++++++++++
 2 files changed, 73 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/bec1443c/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java
index 5753a93..2a3d5a0 100644
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java
@@ -19,6 +19,7 @@
 
 package org.apache.curator.framework.recipes.nodes;
 
+import com.google.common.base.Function;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import org.apache.curator.framework.CuratorFramework;
@@ -28,6 +29,7 @@ import org.apache.curator.framework.api.CreateBuilder;
 import org.apache.curator.framework.api.CreateModable;
 import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.framework.api.CuratorWatcher;
+import org.apache.curator.framework.listen.ListenerContainer;
 import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.utils.PathUtils;
@@ -69,6 +71,7 @@ public class PersistentNode implements Closeable
     private final BackgroundCallback backgroundCallback;
     private final boolean useProtection;
     private final AtomicReference<CreateModable<ACLBackgroundPathAndBytesable<String>>> createMethod = new AtomicReference<CreateModable<ACLBackgroundPathAndBytesable<String>>>(null);
+    private final ListenerContainer<PersistentNodeListener> listeners = new ListenerContainer<PersistentNodeListener>();
     private final CuratorWatcher watcher = new CuratorWatcher()
     {
         @Override
@@ -117,8 +120,8 @@ public class PersistentNode implements Closeable
             {
                 //Update is ok, mark initialisation as complete if required.
                 initialisationComplete();
-            } 
-            else if ( event.getResultCode() == KeeperException.Code.NOAUTH.intValue() ) 
+            }
+            else if ( event.getResultCode() == KeeperException.Code.NOAUTH.intValue() )
             {
                 log.warn("Client does not have authorisation to write node at path {}", event.getPath());
                 authFailure.set(true);
@@ -235,6 +238,7 @@ public class PersistentNode implements Closeable
             else
             {
                 initialisationComplete();
+                notifyListeners();
             }
         }
         else
@@ -303,6 +307,16 @@ public class PersistentNode implements Closeable
     }
 
     /**
+     * Returns the listenable
+     *
+     * @return listenable
+     */
+    public ListenerContainer<PersistentNodeListener> getListenable()
+    {
+        return listeners;
+    }
+
+    /**
      * Returns the currently set path or null if the node does not exist
      *
      * @return node path or null
@@ -427,6 +441,30 @@ public class PersistentNode implements Closeable
         }
     }
 
+    private void notifyListeners()
+    {
+        final String path = getActualPath();
+        listeners.forEach(
+             new Function<PersistentNodeListener, Void>()
+             {
+                 @Override
+                 public Void apply(PersistentNodeListener listener)
+                 {
+                     try
+                    {
+                        listener.nodeCreated(path);
+                    }
+                    catch ( Exception e )
+                    {
+                        ThreadUtils.checkInterrupted(e);
+                        log.error("From PersistentNode listener", e);
+                    }
+                    return null;
+                }
+             }
+        );
+    }
+
     private boolean isActive()
     {
         return (state.get() == State.STARTED);

http://git-wip-us.apache.org/repos/asf/curator/blob/bec1443c/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNodeListener.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNodeListener.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNodeListener.java
new file mode 100644
index 0000000..4131140
--- /dev/null
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNodeListener.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.curator.framework.recipes.nodes;
+
+/**
+ * Listener for changes to a PersistentNode
+ */
+public interface PersistentNodeListener {
+    /**
+     * Called on a persistentNode event when node is created
+     *
+     * @param path Path of the znode
+     * @throws Exception errors
+     */
+    void nodeCreated(String path) throws Exception;
+}


[9/9] curator git commit: Working on strongly typed parameters plus an example that uses it

Posted by ra...@apache.org.
Working on strongly typed parameters plus an example that uses it


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/1fcb63a5
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/1fcb63a5
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/1fcb63a5

Branch: refs/heads/CURATOR-397
Commit: 1fcb63a5c7f29ddbfaedfdd18273ccabff21990e
Parents: 26c7adb
Author: randgalt <ra...@apache.org>
Authored: Tue May 2 17:32:38 2017 -0500
Committer: randgalt <ra...@apache.org>
Committed: Tue May 2 17:32:38 2017 -0500

----------------------------------------------------------------------
 .../java/modeled/ModeledCuratorExamples.java    |  18 +-
 .../java/modeled/ModeledCuratorExamplesAlt.java |   8 +-
 .../src/main/java/modeled/PersonModelSpec.java  |   8 +-
 .../src/main/java/modeledRegistry/Clients.java  |  35 --
 .../main/java/modeledRegistry/ModelSpecs.java   |  37 --
 .../src/main/java/modeledRegistry/Paths.java    |  17 -
 .../java/modeledRegistry/RegistryExamples.java  |  20 --
 .../main/java/modeledRegistry/models/Cache.java |  24 --
 .../java/modeledRegistry/models/Database.java   |  32 --
 .../java/modeledRegistry/models/InstanceId.java |  24 --
 .../java/modeledRegistry/models/Server.java     |  25 --
 .../java/modeledRegistry/models/Session.java    |  24 --
 .../main/java/modeledRegistry/models/Zone.java  |  36 --
 .../main/java/pubsub/InstanceSubscriber.java    |  36 ++
 .../src/main/java/pubsub/MessageSubscriber.java |  37 ++
 .../src/main/java/pubsub/Publisher.java         |  80 +++++
 .../src/main/java/pubsub/SubPubTest.java        |  18 +
 .../src/main/java/pubsub/Subscriber.java        |  15 +
 .../src/main/java/pubsub/builders/Clients.java  |  27 ++
 .../main/java/pubsub/builders/ModelSpecs.java   |  28 ++
 .../src/main/java/pubsub/builders/Paths.java    |  19 ++
 .../java/pubsub/messages/LocationAvailable.java |  26 ++
 .../main/java/pubsub/messages/UserCreated.java  |  35 ++
 .../src/main/java/pubsub/models/Group.java      |  29 ++
 .../src/main/java/pubsub/models/Instance.java   |  52 +++
 .../main/java/pubsub/models/InstanceType.java   |   9 +
 .../src/main/java/pubsub/models/Message.java    |  38 +++
 .../src/main/java/pubsub/models/Priority.java   |   8 +
 .../org/apache/curator/x/async/AsyncStage.java  |   6 +-
 .../x/async/modeled/ModelSpecBuilder.java       |  17 +-
 .../async/modeled/ModeledCuratorFramework.java  | 271 ---------------
 .../modeled/ModeledCuratorFrameworkBuilder.java | 126 -------
 .../x/async/modeled/ModeledFramework.java       | 283 ++++++++++++++++
 .../async/modeled/ModeledFrameworkBuilder.java  | 154 +++++++++
 .../curator/x/async/modeled/NodeName.java       |  16 +
 .../cached/CachedModeledCuratorFramework.java   |  62 ----
 .../modeled/cached/CachedModeledFramework.java  |  62 ++++
 .../CachedModeledCuratorFrameworkImpl.java      | 228 -------------
 .../details/CachedModeledFrameworkImpl.java     | 228 +++++++++++++
 .../x/async/modeled/details/ModelSpecImpl.java  |  12 +-
 .../details/ModeledCuratorFrameworkImpl.java    | 335 -------------------
 .../modeled/details/ModeledFrameworkImpl.java   | 335 +++++++++++++++++++
 .../x/async/modeled/typed/TypedModelSpec.java   |   1 +
 .../x/async/modeled/typed/TypedModelSpec10.java |   1 +
 .../x/async/modeled/typed/TypedModelSpec2.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec3.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec4.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec5.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec6.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec7.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec8.java  |   1 +
 .../x/async/modeled/typed/TypedModelSpec9.java  |   1 +
 .../modeled/typed/TypedModeledFramework.java    |  32 ++
 .../modeled/typed/TypedModeledFramework10.java  |  25 ++
 .../modeled/typed/TypedModeledFramework2.java   |  25 ++
 .../modeled/typed/TypedModeledFramework3.java   |  25 ++
 .../modeled/typed/TypedModeledFramework4.java   |  25 ++
 .../modeled/typed/TypedModeledFramework5.java   |  25 ++
 .../modeled/typed/TypedModeledFramework6.java   |  25 ++
 .../modeled/typed/TypedModeledFramework7.java   |  25 ++
 .../modeled/typed/TypedModeledFramework8.java   |  25 ++
 .../modeled/typed/TypedModeledFramework9.java   |  25 ++
 .../x/async/modeled/typed/TypedZPath.java       |   4 +-
 .../x/async/modeled/typed/TypedZPath10.java     |   4 +-
 .../x/async/modeled/typed/TypedZPath2.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath3.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath4.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath5.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath6.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath7.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath8.java      |   4 +-
 .../x/async/modeled/typed/TypedZPath9.java      |   4 +-
 .../src/site/confluence/index.confluence        |   2 +-
 .../src/site/confluence/modeled.confluence      |   8 +-
 .../modeled/TestModeledCuratorFramework.java    | 122 -------
 .../x/async/modeled/TestModeledFramework.java   | 122 +++++++
 .../TestCachedModeledCuratorFramework.java      |  96 ------
 .../details/TestCachedModeledFramework.java     |  96 ++++++
 78 files changed, 2081 insertions(+), 1572 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeled/ModeledCuratorExamples.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeled/ModeledCuratorExamples.java b/curator-examples/src/main/java/modeled/ModeledCuratorExamples.java
index 3e0d140..7bfc131 100644
--- a/curator-examples/src/main/java/modeled/ModeledCuratorExamples.java
+++ b/curator-examples/src/main/java/modeled/ModeledCuratorExamples.java
@@ -21,13 +21,13 @@ package modeled;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.JacksonModelSerializer;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
 import org.apache.curator.x.async.modeled.ZPath;
 import java.util.function.Consumer;
 
 public class ModeledCuratorExamples
 {
-    public static ModeledCuratorFramework<PersonModel> wrap(CuratorFramework client)
+    public static ModeledFramework<PersonModel> wrap(CuratorFramework client)
     {
         JacksonModelSerializer<PersonModel> serializer = JacksonModelSerializer.build(PersonModel.class);
 
@@ -35,22 +35,22 @@ public class ModeledCuratorExamples
         ModelSpec<PersonModel> modelSpec = ModelSpec.builder(ZPath.parse("/example/path"), serializer).build();
 
         // wrap a CuratorFramework instance so that it can be used "modeled".
-        // do this once and re-use the returned ModeledCuratorFramework instance.
-        // ModeledCuratorFramework instances are tied to a given path
-        return ModeledCuratorFramework.wrap(client, modelSpec);
+        // do this once and re-use the returned ModeledFramework instance.
+        // ModeledFramework instances are tied to a given path
+        return ModeledFramework.wrap(client, modelSpec);
     }
 
-    public static void createOrUpdate(ModeledCuratorFramework<PersonModel> modeled, PersonModel model)
+    public static void createOrUpdate(ModeledFramework<PersonModel> modeled, PersonModel model)
     {
         // change the affected path to be modeled's base path plus id: i.e. "/example/path/{id}"
-        ModeledCuratorFramework<PersonModel> atId = modeled.at(model.getId().getId());
+        ModeledFramework<PersonModel> atId = modeled.at(model.getId().getId());
 
-        // by default ModeledCuratorFramework instances update the node if it already exists
+        // by default ModeledFramework instances update the node if it already exists
         // so this will either create or update the node
         atId.set(model); // note - this is async
     }
 
-    public static void readPerson(ModeledCuratorFramework<PersonModel> modeled, String id, Consumer<PersonModel> receiver)
+    public static void readPerson(ModeledFramework<PersonModel> modeled, String id, Consumer<PersonModel> receiver)
     {
         // read the person with the given ID and asynchronously call the receiver after it is read
         modeled.at(id).read().whenComplete((person, exception) -> {

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeled/ModeledCuratorExamplesAlt.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeled/ModeledCuratorExamplesAlt.java b/curator-examples/src/main/java/modeled/ModeledCuratorExamplesAlt.java
index a8d9bcf..859a1f1 100644
--- a/curator-examples/src/main/java/modeled/ModeledCuratorExamplesAlt.java
+++ b/curator-examples/src/main/java/modeled/ModeledCuratorExamplesAlt.java
@@ -18,7 +18,7 @@
  */
 package modeled;
 
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
 import java.util.function.Consumer;
 
 public class ModeledCuratorExamplesAlt
@@ -26,16 +26,16 @@ public class ModeledCuratorExamplesAlt
     public static void createOrUpdate(PersonModelSpec modelSpec, PersonModel model)
     {
         // change the affected path to be modeled's base path plus id: i.e. "/example/path/{id}"
-        ModeledCuratorFramework<PersonModel> resolved = modelSpec.resolved(model.getContainerType(), model.getId());
+        ModeledFramework<PersonModel> resolved = modelSpec.resolved(model.getContainerType(), model.getId());
 
-        // by default ModeledCuratorFramework instances update the node if it already exists
+        // by default ModeledFramework instances update the node if it already exists
         // so this will either create or update the node
         resolved.set(model); // note - this is async
     }
 
     public static void readPerson(PersonModelSpec modelSpec, ContainerType containerType, PersonId id, Consumer<PersonModel> receiver)
     {
-        ModeledCuratorFramework<PersonModel> resolved = modelSpec.resolved(containerType, id);
+        ModeledFramework<PersonModel> resolved = modelSpec.resolved(containerType, id);
 
         // read the person with the given ID and asynchronously call the receiver after it is read
         resolved.read().whenComplete((person, exception) -> {

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeled/PersonModelSpec.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeled/PersonModelSpec.java b/curator-examples/src/main/java/modeled/PersonModelSpec.java
index 7e0d821..8230f6e 100644
--- a/curator-examples/src/main/java/modeled/PersonModelSpec.java
+++ b/curator-examples/src/main/java/modeled/PersonModelSpec.java
@@ -21,7 +21,7 @@ package modeled;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.JacksonModelSerializer;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
 import org.apache.curator.x.async.modeled.ZPath;
 
 public class PersonModelSpec
@@ -34,13 +34,13 @@ public class PersonModelSpec
         this.client = client;
 
         JacksonModelSerializer<PersonModel> serializer = JacksonModelSerializer.build(PersonModel.class);
-        ZPath path = ZPath.from("example", ZPath.parameterNodeName(), "path", ZPath.parameterNodeName());
+        ZPath path = ZPath.from("example", ZPath.parameterNodeName, "path", ZPath.parameterNodeName);
         modelSpec = ModelSpec.builder(path, serializer).build();
     }
 
-    public ModeledCuratorFramework<PersonModel> resolved(ContainerType containerType, PersonId personId)
+    public ModeledFramework<PersonModel> resolved(ContainerType containerType, PersonId personId)
     {
         ModelSpec<PersonModel> resolved = null;// TODO modelSpec.resolved(containerType.getTypeId(), personId.getId());
-        return ModeledCuratorFramework.wrap(client, resolved);
+        return ModeledFramework.wrap(client, resolved);
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/Clients.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/Clients.java b/curator-examples/src/main/java/modeledRegistry/Clients.java
deleted file mode 100644
index e9071e7..0000000
--- a/curator-examples/src/main/java/modeledRegistry/Clients.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package modeledRegistry;
-
-import modeledRegistry.models.Cache;
-import modeledRegistry.models.Database;
-import modeledRegistry.models.InstanceId;
-import modeledRegistry.models.Session;
-import modeledRegistry.models.Zone;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
-
-import static modeledRegistry.ModelSpecs.cacheModelSpec;
-import static modeledRegistry.ModelSpecs.databaseModelSpec;
-import static modeledRegistry.ModelSpecs.sessionModelSpec;
-
-public class Clients
-{
-    public static ModeledCuratorFramework<Cache> cacheClient(CuratorFramework client, Zone zone, InstanceId id)
-    {
-        return ModeledCuratorFramework.wrap(client, cacheModelSpec.resolved(zone, id));
-    }
-
-    public static ModeledCuratorFramework<Session> sessionClient(CuratorFramework client, Zone zone, InstanceId id)
-    {
-        return ModeledCuratorFramework.wrap(client, sessionModelSpec.resolved(zone, id));
-    }
-
-    public static ModeledCuratorFramework<Database> databaseClient(CuratorFramework client, Zone zone)
-    {
-        return ModeledCuratorFramework.wrap(client, databaseModelSpec.resolved(zone));
-    }
-
-    private Clients()
-    {
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/ModelSpecs.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/ModelSpecs.java b/curator-examples/src/main/java/modeledRegistry/ModelSpecs.java
deleted file mode 100644
index 96469cc..0000000
--- a/curator-examples/src/main/java/modeledRegistry/ModelSpecs.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package modeledRegistry;
-
-import modeledRegistry.models.Cache;
-import modeledRegistry.models.Database;
-import modeledRegistry.models.InstanceId;
-import modeledRegistry.models.Session;
-import modeledRegistry.models.Zone;
-import org.apache.curator.x.async.modeled.JacksonModelSerializer;
-import org.apache.curator.x.async.modeled.ModelSpec;
-import org.apache.curator.x.async.modeled.typed.TypedModelSpec;
-import org.apache.curator.x.async.modeled.typed.TypedModelSpec2;
-
-import static modeledRegistry.Paths.cachePath;
-import static modeledRegistry.Paths.databasePath;
-import static modeledRegistry.Paths.sessionPath;
-
-public class ModelSpecs
-{
-    public static final TypedModelSpec2<Cache, Zone, InstanceId> cacheModelSpec = TypedModelSpec2.from(
-        ModelSpec.builder(JacksonModelSerializer.build(Cache.class)).withNodeName(Cache::getId),
-        cachePath
-    );
-
-    public static final TypedModelSpec2<Session, Zone, InstanceId> sessionModelSpec = TypedModelSpec2.from(
-        ModelSpec.builder(JacksonModelSerializer.build(Session.class)).withNodeName(Session::getId),
-        sessionPath
-    );
-
-    public static final TypedModelSpec<Database, Zone> databaseModelSpec = TypedModelSpec.from(
-        ModelSpec.builder(JacksonModelSerializer.build(Database.class)).withNodeName(Database::getServerName),
-        databasePath
-    );
-
-    private ModelSpecs()
-    {
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/Paths.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/Paths.java b/curator-examples/src/main/java/modeledRegistry/Paths.java
deleted file mode 100644
index de23aa4..0000000
--- a/curator-examples/src/main/java/modeledRegistry/Paths.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package modeledRegistry;
-
-import modeledRegistry.models.InstanceId;
-import modeledRegistry.models.Zone;
-import org.apache.curator.x.async.modeled.typed.TypedZPath;
-import org.apache.curator.x.async.modeled.typed.TypedZPath2;
-
-public class Paths
-{
-    public static final TypedZPath2<Zone, InstanceId> cachePath = TypedZPath2.from("/root/registry/{id}/{id}/caches");
-    public static final TypedZPath2<Zone, InstanceId> sessionPath = TypedZPath2.from("/root/registry/{id}/{id}/sessions");
-    public static final TypedZPath<Zone> databasePath = TypedZPath.from("/root/registry/{id}/dbs");
-
-    private Paths()
-    {
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/RegistryExamples.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/RegistryExamples.java b/curator-examples/src/main/java/modeledRegistry/RegistryExamples.java
deleted file mode 100644
index c344dd9..0000000
--- a/curator-examples/src/main/java/modeledRegistry/RegistryExamples.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package modeledRegistry;
-
-import modeledRegistry.models.Database;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
-import java.util.List;
-import java.util.function.Consumer;
-
-public class RegistryExamples
-{
-    public static void addDatabase(ModeledCuratorFramework<Database> client, Database database)
-    {
-        ModeledCuratorFramework<Database> resolved = client.resolved(database);
-        resolved.set(database);
-    }
-
-    public static void getDatabases(ModeledCuratorFramework<Database> client, Consumer<List<Database>> consumer)
-    {
-//        client.children().thenCombine();
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/models/Cache.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/models/Cache.java b/curator-examples/src/main/java/modeledRegistry/models/Cache.java
deleted file mode 100644
index a148a5f..0000000
--- a/curator-examples/src/main/java/modeledRegistry/models/Cache.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package modeledRegistry.models;
-
-import java.util.UUID;
-
-public class Cache extends Server
-{
-    private final int maxObjects;
-
-    public Cache()
-    {
-        this(UUID.randomUUID().toString(), "localhost", Integer.MAX_VALUE);
-    }
-
-    public Cache(String id, String ipAddress, int maxObjects)
-    {
-        super(id, ipAddress);
-        this.maxObjects = maxObjects;
-    }
-
-    public int getMaxObjects()
-    {
-        return maxObjects;
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/models/Database.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/models/Database.java b/curator-examples/src/main/java/modeledRegistry/models/Database.java
deleted file mode 100644
index 681ed34..0000000
--- a/curator-examples/src/main/java/modeledRegistry/models/Database.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package modeledRegistry.models;
-
-import java.util.Objects;
-import java.util.UUID;
-
-public class Database extends Server
-{
-    private final String connectionString;
-    private final String serverName;
-
-    public Database()
-    {
-        this(UUID.randomUUID().toString(), "localhost", "", "");
-    }
-
-    public Database(String id, String ipAddress, String serverName, String connectionString)
-    {
-        super(id, ipAddress);
-        this.serverName = Objects.requireNonNull(serverName, "serverName cannot be null");
-        this.connectionString = Objects.requireNonNull(connectionString, "connectionString cannot be null");
-    }
-
-    public String getConnectionString()
-    {
-        return connectionString;
-    }
-
-    public String getServerName()
-    {
-        return serverName;
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/models/InstanceId.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/models/InstanceId.java b/curator-examples/src/main/java/modeledRegistry/models/InstanceId.java
deleted file mode 100644
index 24ab98e..0000000
--- a/curator-examples/src/main/java/modeledRegistry/models/InstanceId.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package modeledRegistry.models;
-
-import java.util.Objects;
-import java.util.UUID;
-
-public class InstanceId
-{
-    private final String id;
-
-    public InstanceId()
-    {
-        this(UUID.randomUUID().toString());
-    }
-
-    public InstanceId(String id)
-    {
-        this.id = Objects.requireNonNull(id, "id cannot be null");
-    }
-
-    public String getId()
-    {
-        return id;
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/models/Server.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/models/Server.java b/curator-examples/src/main/java/modeledRegistry/models/Server.java
deleted file mode 100644
index 9085b0f..0000000
--- a/curator-examples/src/main/java/modeledRegistry/models/Server.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package modeledRegistry.models;
-
-import java.util.Objects;
-
-public abstract class Server
-{
-    private final String id;
-    private final String ipAddress;
-
-    protected Server(String id, String ipAddress)
-    {
-        this.id = Objects.requireNonNull(id, "id cannot be null");
-        this.ipAddress = Objects.requireNonNull(ipAddress, "ipAddress cannot be null");
-    }
-
-    public String getId()
-    {
-        return id;
-    }
-
-    public String getIpAddress()
-    {
-        return ipAddress;
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/models/Session.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/models/Session.java b/curator-examples/src/main/java/modeledRegistry/models/Session.java
deleted file mode 100644
index 230dec2..0000000
--- a/curator-examples/src/main/java/modeledRegistry/models/Session.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package modeledRegistry.models;
-
-import java.util.UUID;
-
-public class Session extends Server
-{
-    private final long ttl;
-
-    public Session()
-    {
-        this(UUID.randomUUID().toString(), "localhost", Long.MAX_VALUE);
-    }
-
-    public Session(String id, String ipAddress, long ttl)
-    {
-        super(id, ipAddress);
-        this.ttl = ttl;
-    }
-
-    public long getTtl()
-    {
-        return ttl;
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/modeledRegistry/models/Zone.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/modeledRegistry/models/Zone.java b/curator-examples/src/main/java/modeledRegistry/models/Zone.java
deleted file mode 100644
index c0f094e..0000000
--- a/curator-examples/src/main/java/modeledRegistry/models/Zone.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package modeledRegistry.models;
-
-import java.util.Objects;
-import java.util.UUID;
-
-public class Zone
-{
-    private final String id;
-    private final String name;
-
-    public Zone()
-    {
-        this(UUID.randomUUID().toString(), "");
-    }
-
-    public Zone(String name)
-    {
-        this(UUID.randomUUID().toString(), name);
-    }
-
-    public Zone(String id, String name)
-    {
-        this.id = Objects.requireNonNull(id, "id cannot be null");
-        this.name = Objects.requireNonNull(name, "name cannot be null");
-    }
-
-    public String getId()
-    {
-        return id;
-    }
-
-    public String getName()
-    {
-        return name;
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/InstanceSubscriber.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/InstanceSubscriber.java b/curator-examples/src/main/java/pubsub/InstanceSubscriber.java
new file mode 100644
index 0000000..d820014
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/InstanceSubscriber.java
@@ -0,0 +1,36 @@
+package pubsub;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.listen.Listenable;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import org.apache.curator.x.async.modeled.cached.ModeledCacheListener;
+import pubsub.builders.Clients;
+import pubsub.models.Instance;
+import pubsub.models.InstanceType;
+import java.io.Closeable;
+
+public class InstanceSubscriber implements Closeable
+{
+    private final CachedModeledFramework<Instance> client;
+
+    public InstanceSubscriber(CuratorFramework client, InstanceType instanceType)
+    {
+        this.client = Clients.instanceClient.resolved(client, instanceType).cached();
+    }
+
+    public Listenable<ModeledCacheListener<Instance>> listenable()
+    {
+        return client.getCache().listenable();
+    }
+
+    public void start()
+    {
+        client.start();
+    }
+
+    @Override
+    public void close()
+    {
+        client.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/MessageSubscriber.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/MessageSubscriber.java b/curator-examples/src/main/java/pubsub/MessageSubscriber.java
new file mode 100644
index 0000000..64ba867
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/MessageSubscriber.java
@@ -0,0 +1,37 @@
+package pubsub;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.listen.Listenable;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import org.apache.curator.x.async.modeled.cached.ModeledCacheListener;
+import pubsub.builders.Clients;
+import pubsub.models.Group;
+import pubsub.models.Message;
+import pubsub.models.Priority;
+import java.io.Closeable;
+
+public class MessageSubscriber implements Closeable
+{
+    private final CachedModeledFramework<Message> client;
+
+    public MessageSubscriber(CuratorFramework client, Group group, Priority priority)
+    {
+        this.client = Clients.messageClient.resolved(client, group, priority).cached();
+    }
+
+    public Listenable<ModeledCacheListener<Message>> listenable()
+    {
+        return client.getCache().listenable();
+    }
+
+    public void start()
+    {
+        client.start();
+    }
+
+    @Override
+    public void close()
+    {
+        client.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/Publisher.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/Publisher.java b/curator-examples/src/main/java/pubsub/Publisher.java
new file mode 100644
index 0000000..b86d2a2
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/Publisher.java
@@ -0,0 +1,80 @@
+package pubsub;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.transaction.CuratorOp;
+import org.apache.curator.x.async.AsyncCuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pubsub.models.Group;
+import pubsub.models.Instance;
+import pubsub.models.Message;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static pubsub.builders.Clients.instanceClient;
+import static pubsub.builders.Clients.messageClient;
+
+public class Publisher
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final AsyncCuratorFramework client;
+
+    public Publisher(CuratorFramework client)
+    {
+        this.client = AsyncCuratorFramework.wrap(Objects.requireNonNull(client, "client cannot be null"));
+    }
+
+    public void publishInstance(Instance instance)
+    {
+        ModeledFramework<Instance> resolvedClient = instanceClient
+            .resolved(client.unwrap(), instance.getType())
+            .resolved(instance);
+        resolvedClient.set(instance).exceptionally(e -> {
+            log.error("Could not publish instance: " + instance, e);
+            return null;
+        });
+    }
+
+    public void publishInstances(List<Instance> instances)
+    {
+        List<CuratorOp> operations = instances.stream()
+            .map(instance -> instanceClient
+                .resolved(client.unwrap(), instance.getType())
+                .resolved(instance)
+                .createOp(instance)
+            )
+            .collect(Collectors.toList());
+        client.transaction().forOperations(operations).exceptionally(e -> {
+            log.error("Could not publish instances: " + instances, e);
+            return null;
+        });
+    }
+
+    public void publishMessage(Message message, Group group)
+    {
+        ModeledFramework<Message> resolvedClient = messageClient
+            .resolved(client.unwrap(), group, message.getPriority())
+            .resolved(message);
+        resolvedClient.set(message).exceptionally(e -> {
+            log.error("Could not publish message: " + message, e);
+            return null;
+        });
+    }
+
+    public void publishMessages(List<Message> messages, Group group)
+    {
+        List<CuratorOp> operations = messages.stream()
+            .map(message -> messageClient
+                    .resolved(client.unwrap(), group, message.getPriority())
+                    .resolved(message)
+                    .createOp(message)
+                )
+            .collect(Collectors.toList());
+        client.transaction().forOperations(operations).exceptionally(e -> {
+            log.error("Could not publish messages: " + messages, e);
+            return null;
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/SubPubTest.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/SubPubTest.java b/curator-examples/src/main/java/pubsub/SubPubTest.java
new file mode 100644
index 0000000..0ba638f
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/SubPubTest.java
@@ -0,0 +1,18 @@
+package pubsub;
+
+import org.apache.curator.test.TestingServer;
+
+public class SubPubTest
+{
+    private final TestingServer testingServer;
+
+    public static void main(String[] args)
+    {
+
+    }
+
+    public SubPubTest() throws Exception
+    {
+        this.testingServer = new TestingServer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/Subscriber.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/Subscriber.java b/curator-examples/src/main/java/pubsub/Subscriber.java
new file mode 100644
index 0000000..ea6de01
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/Subscriber.java
@@ -0,0 +1,15 @@
+package pubsub;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import pubsub.messages.LocationAvailable;
+
+public class Subscriber
+{
+    private final CuratorFramework client;
+
+    public Subscriber(CuratorFramework client)
+    {
+        this.client = client;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/builders/Clients.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/builders/Clients.java b/curator-examples/src/main/java/pubsub/builders/Clients.java
new file mode 100644
index 0000000..e2b1c89
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/builders/Clients.java
@@ -0,0 +1,27 @@
+package pubsub.builders;
+
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.typed.TypedModeledFramework;
+import org.apache.curator.x.async.modeled.typed.TypedModeledFramework2;
+import pubsub.models.Group;
+import pubsub.models.Instance;
+import pubsub.models.InstanceType;
+import pubsub.models.Message;
+import pubsub.models.Priority;
+
+public class Clients
+{
+    public static final TypedModeledFramework2<Message, Group, Priority> messageClient = TypedModeledFramework2.from(
+        ModeledFramework.builder(),
+        ModelSpecs.messageModelSpec
+    );
+
+    public static final TypedModeledFramework<Instance, InstanceType> instanceClient = TypedModeledFramework.from(
+        ModeledFramework.builder(),
+        ModelSpecs.instanceModelSpec
+    );
+
+    private Clients()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/builders/ModelSpecs.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/builders/ModelSpecs.java b/curator-examples/src/main/java/pubsub/builders/ModelSpecs.java
new file mode 100644
index 0000000..83cdfe4
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/builders/ModelSpecs.java
@@ -0,0 +1,28 @@
+package pubsub.builders;
+
+import org.apache.curator.x.async.modeled.JacksonModelSerializer;
+import org.apache.curator.x.async.modeled.ModelSpec;
+import org.apache.curator.x.async.modeled.typed.TypedModelSpec;
+import org.apache.curator.x.async.modeled.typed.TypedModelSpec2;
+import pubsub.models.Group;
+import pubsub.models.Instance;
+import pubsub.models.InstanceType;
+import pubsub.models.Message;
+import pubsub.models.Priority;
+
+public class ModelSpecs
+{
+    public static final TypedModelSpec2<Message, Group, Priority> messageModelSpec = TypedModelSpec2.from(
+        ModelSpec.builder(JacksonModelSerializer.build(Message.class)),
+        Paths.messagesPath
+    );
+
+    public static final TypedModelSpec<Instance, InstanceType> instanceModelSpec = TypedModelSpec.from(
+        ModelSpec.builder(JacksonModelSerializer.build(Instance.class)),
+        Paths.instancesPath
+    );
+
+    private ModelSpecs()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/builders/Paths.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/builders/Paths.java b/curator-examples/src/main/java/pubsub/builders/Paths.java
new file mode 100644
index 0000000..0db5138
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/builders/Paths.java
@@ -0,0 +1,19 @@
+package pubsub.builders;
+
+import org.apache.curator.x.async.modeled.typed.TypedZPath;
+import org.apache.curator.x.async.modeled.typed.TypedZPath2;
+import pubsub.models.Group;
+import pubsub.models.InstanceType;
+import pubsub.models.Priority;
+
+public class Paths
+{
+    private static final String basePath = "/root/pubsub";
+
+    public static final TypedZPath2<Group, Priority> messagesPath = TypedZPath2.from(basePath + "/messages/{id}/{id}");
+    public static final TypedZPath<InstanceType> instancesPath = TypedZPath.from(basePath + "/instances/{id}");
+
+    private Paths()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/messages/LocationAvailable.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/messages/LocationAvailable.java b/curator-examples/src/main/java/pubsub/messages/LocationAvailable.java
new file mode 100644
index 0000000..503e4ed
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/messages/LocationAvailable.java
@@ -0,0 +1,26 @@
+package pubsub.messages;
+
+import pubsub.models.Message;
+import pubsub.models.Priority;
+import java.time.Duration;
+import java.util.Objects;
+
+public class LocationAvailable extends Message
+{
+    private final String name;
+    private final Duration availableUntil;
+
+    public LocationAvailable(Priority priority, String name, Duration availableUntil)
+    {
+        super(priority);
+        this.name = Objects.requireNonNull(name, "name cannot be null");
+        this.availableUntil = Objects.requireNonNull(availableUntil, "availableUntil cannot be null");
+    }
+
+    public LocationAvailable(String id, Priority priority, String name, Duration availableUntil)
+    {
+        super(id, priority);
+        this.name = Objects.requireNonNull(name, "name cannot be null");
+        this.availableUntil = Objects.requireNonNull(availableUntil, "availableUntil cannot be null");
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/messages/UserCreated.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/messages/UserCreated.java b/curator-examples/src/main/java/pubsub/messages/UserCreated.java
new file mode 100644
index 0000000..da7e639
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/messages/UserCreated.java
@@ -0,0 +1,35 @@
+package pubsub.messages;
+
+import pubsub.models.Message;
+import pubsub.models.Priority;
+import java.util.Objects;
+
+public class UserCreated extends Message
+{
+    private final String name;
+    private final String position;
+
+    public UserCreated(Priority priority, String name, String position)
+    {
+        super(priority);
+        this.name = Objects.requireNonNull(name, "name cannot be null");
+        this.position = Objects.requireNonNull(position, "position cannot be null");
+    }
+
+    public UserCreated(String id, Priority priority, String name, String position)
+    {
+        super(id, priority);
+        this.name = Objects.requireNonNull(name, "name cannot be null");
+        this.position = Objects.requireNonNull(position, "position cannot be null");
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public String getPosition()
+    {
+        return position;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/models/Group.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/models/Group.java b/curator-examples/src/main/java/pubsub/models/Group.java
new file mode 100644
index 0000000..a9636a4
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/models/Group.java
@@ -0,0 +1,29 @@
+package pubsub.models;
+
+import org.apache.curator.x.async.modeled.NodeName;
+
+public class Group implements NodeName
+{
+    private final String groupName;
+
+    public Group()
+    {
+        this("");
+    }
+
+    public Group(String groupName)
+    {
+        this.groupName = groupName;
+    }
+
+    public String getGroupName()
+    {
+        return groupName;
+    }
+
+    @Override
+    public String nodeName()
+    {
+        return groupName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/models/Instance.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/models/Instance.java b/curator-examples/src/main/java/pubsub/models/Instance.java
new file mode 100644
index 0000000..d674317
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/models/Instance.java
@@ -0,0 +1,52 @@
+package pubsub.models;
+
+import org.apache.curator.x.async.modeled.NodeName;
+import java.util.Objects;
+import java.util.UUID;
+
+public class Instance implements NodeName
+{
+    private final String id;
+    private final InstanceType type;
+    private final String hostname;
+    private final int port;
+
+    public Instance()
+    {
+        this(UUID.randomUUID().toString(), InstanceType.proxy, "", 0);
+    }
+
+    public Instance(String id, InstanceType type, String hostname, int port)
+    {
+        this.id = Objects.requireNonNull(id, "id cannot be null");
+        this.type = Objects.requireNonNull(type, "type cannot be null");
+        this.hostname = Objects.requireNonNull(hostname, "hostname cannot be null");
+        this.port = port;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public InstanceType getType()
+    {
+        return type;
+    }
+
+    public String getHostname()
+    {
+        return hostname;
+    }
+
+    public int getPort()
+    {
+        return port;
+    }
+
+    @Override
+    public String nodeName()
+    {
+        return id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/models/InstanceType.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/models/InstanceType.java b/curator-examples/src/main/java/pubsub/models/InstanceType.java
new file mode 100644
index 0000000..f1daea0
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/models/InstanceType.java
@@ -0,0 +1,9 @@
+package pubsub.models;
+
+public enum InstanceType
+{
+    database,
+    cache,
+    web,
+    proxy
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/models/Message.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/models/Message.java b/curator-examples/src/main/java/pubsub/models/Message.java
new file mode 100644
index 0000000..27a0268
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/models/Message.java
@@ -0,0 +1,38 @@
+package pubsub.models;
+
+import org.apache.curator.x.async.modeled.NodeName;
+import java.util.Objects;
+import java.util.UUID;
+
+public abstract class Message implements NodeName
+{
+    private final String id;
+    private final Priority priority;
+
+    protected Message(Priority priority)
+    {
+        this(UUID.randomUUID().toString(), priority);
+    }
+
+    protected Message(String id, Priority priority)
+    {
+        this.id = Objects.requireNonNull(id, "id cannot be null");
+        this.priority = Objects.requireNonNull(priority, "messageType cannot be null");
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public Priority getPriority()
+    {
+        return priority;
+    }
+
+    @Override
+    public String nodeName()
+    {
+        return id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-examples/src/main/java/pubsub/models/Priority.java
----------------------------------------------------------------------
diff --git a/curator-examples/src/main/java/pubsub/models/Priority.java b/curator-examples/src/main/java/pubsub/models/Priority.java
new file mode 100644
index 0000000..ea8051e
--- /dev/null
+++ b/curator-examples/src/main/java/pubsub/models/Priority.java
@@ -0,0 +1,8 @@
+package pubsub.models;
+
+public enum Priority
+{
+    low,
+    medium,
+    high
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/AsyncStage.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/AsyncStage.java b/curator-x-async/src/main/java/org/apache/curator/x/async/AsyncStage.java
index 331cd16..ad7547b 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/AsyncStage.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/AsyncStage.java
@@ -34,9 +34,9 @@ public interface AsyncStage<T> extends CompletionStage<T>
      * </p>
      *
      * <p>
-     *     Also, applies to {@link org.apache.curator.x.async.modeled.ModeledCuratorFramework}
-     *     when {@link org.apache.curator.x.async.modeled.ModeledCuratorFrameworkBuilder#watched(WatchMode)}
-     *     or {@link org.apache.curator.x.async.modeled.ModeledCuratorFrameworkBuilder#watched(WatchMode, java.util.function.UnaryOperator)}
+     *     Also, applies to {@link org.apache.curator.x.async.modeled.ModeledFramework}
+     *     when {@link org.apache.curator.x.async.modeled.ModeledFrameworkBuilder#watched(WatchMode)}
+     *     or {@link org.apache.curator.x.async.modeled.ModeledFrameworkBuilder#watched(WatchMode, java.util.function.UnaryOperator)}
      *     is used.
      * </p>
      *

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSpecBuilder.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSpecBuilder.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSpecBuilder.java
index 16e7696..2ac2501 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSpecBuilder.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSpecBuilder.java
@@ -28,7 +28,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.function.Function;
 
 public class ModelSpecBuilder<T>
 {
@@ -38,7 +37,6 @@ public class ModelSpecBuilder<T>
     private List<ACL> aclList = Collections.emptyList();
     private Set<CreateOption> createOptions = Collections.emptySet();
     private Set<DeleteOption> deleteOptions = Collections.emptySet();
-    private Function<T, String> nodeName = Object::toString;
 
     /**
      * Build a new ModelSpec instance
@@ -47,7 +45,7 @@ public class ModelSpecBuilder<T>
      */
     public ModelSpec<T> build()
     {
-        return new ModelSpecImpl<>(path, serializer, createMode, aclList, createOptions, deleteOptions, nodeName);
+        return new ModelSpecImpl<>(path, serializer, createMode, aclList, createOptions, deleteOptions);
     }
 
     /**
@@ -99,19 +97,6 @@ public class ModelSpecBuilder<T>
     }
 
     /**
-     * Functor that returns the node name to use for a model instance. Default is to call
-     * <code>toString()</code> on the model instance.
-     *
-     * @param nodeName naming functor
-     * @return this for chaining
-     */
-    public ModelSpecBuilder<T> withNodeName(Function<T, String> nodeName)
-    {
-        this.nodeName = Objects.requireNonNull(nodeName, "nodeName cannot be null");
-        return this;
-    }
-
-    /**
      * Change the model spec's path
      *
      * @param path new path

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFramework.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFramework.java
deleted file mode 100644
index 85d0e30..0000000
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFramework.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * 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.curator.x.async.modeled;
-
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.api.transaction.CuratorOp;
-import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
-import org.apache.curator.x.async.AsyncStage;
-import org.apache.curator.x.async.modeled.cached.CachedModeledCuratorFramework;
-import org.apache.zookeeper.data.Stat;
-import java.util.List;
-
-public interface ModeledCuratorFramework<T>
-{
-    /**
-     * Return a new ModeledCuratorFramework for the given model
-     *
-     * @param client Curator client
-     * @param model the model
-     * @return new Modeled Curator instance
-     */
-    static <T> ModeledCuratorFramework<T> wrap(CuratorFramework client, ModelSpec<T> model)
-    {
-        return builder(client, model).build();
-    }
-
-    /**
-     * Start a new ModeledCuratorFrameworkBuilder for the given model
-     *
-     * @param client Curator client
-     * @param model the model
-     * @return builder
-     */
-    static <T> ModeledCuratorFrameworkBuilder<T> builder(CuratorFramework client, ModelSpec<T> model)
-    {
-        return new ModeledCuratorFrameworkBuilder<>(client, model);
-    }
-
-    /**
-     * Use an internally created cache as a front for this modeled instance. All read APIs check the cache
-     * first and, if available, return the values from the cache. Note: you must call
-     * {@link org.apache.curator.x.async.modeled.cached.CachedModeledCuratorFramework#start()} and
-     * {@link CachedModeledCuratorFramework#close()} to start/stop
-     *
-     * @return wrapped instance
-     */
-    CachedModeledCuratorFramework<T> cached();
-
-    /**
-     * Returns the client that was originally passed to {@link #wrap(org.apache.curator.framework.CuratorFramework, ModelSpec)} or
-     * the builder.
-     *
-     * @return original client
-     */
-    CuratorFramework unwrap();
-
-    /**
-     * Return the model being used
-     *
-     * @return model
-     */
-    ModelSpec<T> modelSpec();
-
-    /**
-     * Return a new Modeled Curator instance with all the same options but applying to the given child node of this Modeled Curator's
-     * path. E.g. if this Modeled Curator instance applies to "/a/b", calling <code>modeled.at("c")</code> returns an instance that applies to
-     * "/a/b/c".
-     *
-     * @param child child node.
-     * @return new Modeled Curator instance
-     */
-    ModeledCuratorFramework<T> at(String child);
-
-    /**
-     * Return a Modeled Curator instance with all the same options but using the given path.
-     *
-     * @param path new path
-     * @return new Modeled Curator instance
-     */
-    ModeledCuratorFramework<T> at(ZPath path);
-
-    /**
-     * Return a new Modeled Curator instance with all the same options but using the
-     * {@link ModelSpecBuilder#nodeName} functor
-     * to generate the child node's name
-     *
-     * @param model model to use to generate the name
-     * @return new Modeled Curator instance
-     */
-    ModeledCuratorFramework<T> resolved(T model);
-
-    /**
-     * Create (or update depending on build options) a ZNode at this instance's path with a serialized
-     * version of the given model
-     *
-     * @param model model to write
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<String> set(T model);
-
-    /**
-     * Create (or update depending on build options) a ZNode at this instance's path with a serialized
-     * form of the given model
-     *
-     * @param model model to write
-     * @param storingStatIn the stat for the new ZNode is stored here
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<String> set(T model, Stat storingStatIn);
-
-    /**
-     * Read the ZNode at this instance's path and deserialize into a model
-     *
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<T> read();
-
-    /**
-     * Read the ZNode at this instance's path and deserialize into a model
-     *
-     * @param storingStatIn the stat for the new ZNode is stored here
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<T> read(Stat storingStatIn);
-
-    /**
-     * Update the ZNode at this instance's path with a serialized
-     * form of the given model passing "-1" for the update version
-     *
-     * @param model model to write
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<Stat> update(T model);
-
-    /**
-     * Update the ZNode at this instance's path with a serialized
-     * form of the given model passing the given update version
-     *
-     * @param model model to write
-     * @param version update version to use
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<Stat> update(T model, int version);
-
-    /**
-     * Delete the ZNode at this instance's path passing -1 for the delete version
-     *
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<Void> delete();
-
-    /**
-     * Delete the ZNode at this instance's path passing the given delete version
-     *
-     * @param version update version to use
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<Void> delete(int version);
-
-    /**
-     * Check to see if the ZNode at this instance's path exists
-     *
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<Stat> checkExists();
-
-    /**
-     * Return the child paths of this instance's path (in no particular order)
-     *
-     * @return AsyncStage
-     * @see org.apache.curator.x.async.AsyncStage
-     */
-    AsyncStage<List<ZPath>> children();
-
-    /**
-     * Create operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction. Note:
-     * due to ZooKeeper transaction limits, this is a _not_ a "set or update" operation but only
-     * a create operation and will generate an error if the node already exists.
-     *
-     * @param model the model
-     * @return operation
-     */
-    CuratorOp createOp(T model);
-
-    /**
-     * Update operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
-     *
-     * @param model the model
-     * @return operation
-     */
-    CuratorOp updateOp(T model);
-
-    /**
-     * Create operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
-     *
-     * @param model the model
-     * @param version update version to use
-     * @return operation
-     */
-    CuratorOp updateOp(T model, int version);
-
-    /**
-     * Delete operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
-     *
-     * @return operation
-     */
-    CuratorOp deleteOp();
-
-    /**
-     * Delete operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
-     *
-     * @param version delete version to use
-     * @return operation
-     */
-    CuratorOp deleteOp(int version);
-
-    /**
-     * Check exists operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
-     *
-     * @return operation
-     */
-    CuratorOp checkExistsOp();
-
-    /**
-     * Check exists operation instance that can be passed among other operations to
-     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
-     *
-     * @param version version to use
-     * @return operation
-     */
-    CuratorOp checkExistsOp(int version);
-
-    /**
-     * Invoke ZooKeeper to commit the given operations as a single transaction.
-     *
-     * @param operations operations that make up the transaction.
-     * @return AsyncStage instance for managing the completion
-     */
-    AsyncStage<List<CuratorTransactionResult>> inTransaction(List<CuratorOp> operations);
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFrameworkBuilder.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFrameworkBuilder.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFrameworkBuilder.java
deleted file mode 100644
index 37224ff..0000000
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledCuratorFrameworkBuilder.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * 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.curator.x.async.modeled;
-
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.api.CuratorEvent;
-import org.apache.curator.framework.api.UnhandledErrorListener;
-import org.apache.curator.x.async.WatchMode;
-import org.apache.curator.x.async.modeled.details.ModeledCuratorFrameworkImpl;
-import org.apache.zookeeper.WatchedEvent;
-import java.util.Objects;
-import java.util.function.UnaryOperator;
-
-public class ModeledCuratorFrameworkBuilder<T>
-{
-    private final CuratorFramework client;
-    private final ModelSpec<T> model;
-    private WatchMode watchMode;
-    private UnaryOperator<WatchedEvent> watcherFilter;
-    private UnhandledErrorListener unhandledErrorListener;
-    private UnaryOperator<CuratorEvent> resultFilter;
-
-    /**
-     * Build a new ModeledCuratorFramework instance
-     *
-     * @return new ModeledCuratorFramework instance
-     */
-    public ModeledCuratorFramework<T> build()
-    {
-        return ModeledCuratorFrameworkImpl.build(
-            client,
-            model,
-            watchMode,
-            watcherFilter,
-            unhandledErrorListener,
-            resultFilter
-        );
-    }
-
-    /**
-     * Add watchers as appropriate to the Modeled Curator's ZNode using
-     * {@link org.apache.curator.x.async.WatchMode#stateChangeAndSuccess}
-     *
-     * @return this for chaining
-     * @see org.apache.curator.x.async.AsyncStage#event()
-     */
-    public ModeledCuratorFrameworkBuilder<T> watched()
-    {
-        this.watchMode = WatchMode.stateChangeAndSuccess;
-        return this;
-    }
-
-    /**
-     * Add watchers as appropriate using the given watchMode to the Modeled Curator's ZNode
-     *
-     * @param watchMode watcher style
-     * @return this for chaining
-     * @see org.apache.curator.x.async.AsyncStage#event()
-     */
-    public ModeledCuratorFrameworkBuilder<T> watched(WatchMode watchMode)
-    {
-        this.watchMode = watchMode;
-        return this;
-    }
-
-    /**
-     * Add watchers as appropriate using the given watchMode and filter to the Modeled Curator's ZNode
-     *
-     * @param watchMode watcher style
-     * @param watcherFilter filter
-     * @return this for chaining
-     * @see org.apache.curator.x.async.AsyncStage#event()
-     */
-    public ModeledCuratorFrameworkBuilder<T> watched(WatchMode watchMode, UnaryOperator<WatchedEvent> watcherFilter)
-    {
-        this.watchMode = watchMode;
-        this.watcherFilter = watcherFilter;
-        return this;
-    }
-
-    /**
-     * Use the given unhandledErrorListener for operations on the Modeled Curator's ZNode
-     *
-     * @param unhandledErrorListener listener
-     * @return this for chaining
-     */
-    public ModeledCuratorFrameworkBuilder<T> withUnhandledErrorListener(UnhandledErrorListener unhandledErrorListener)
-    {
-        this.unhandledErrorListener = unhandledErrorListener;
-        return this;
-    }
-
-    /**
-     * Use the given result filter for operations on the Modeled Curator's ZNode
-     *
-     * @param resultFilter filter
-     * @return this for chaining
-     */
-    public ModeledCuratorFrameworkBuilder<T> withResultFilter(UnaryOperator<CuratorEvent> resultFilter)
-    {
-        this.resultFilter = resultFilter;
-        return this;
-    }
-
-    ModeledCuratorFrameworkBuilder(CuratorFramework client, ModelSpec<T> model)
-    {
-        this.client = Objects.requireNonNull(client, "client cannot be null");
-        this.model = Objects.requireNonNull(model, "model cannot be null");
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFramework.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFramework.java
new file mode 100644
index 0000000..7b88625
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFramework.java
@@ -0,0 +1,283 @@
+/**
+ * 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.curator.x.async.modeled;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.transaction.CuratorOp;
+import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
+import org.apache.curator.x.async.AsyncStage;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import org.apache.zookeeper.data.Stat;
+import java.util.List;
+
+public interface ModeledFramework<T>
+{
+    /**
+     * Return a new ModeledFramework for the given model
+     *
+     * @param client Curator client
+     * @param model the model
+     * @return new Modeled Curator instance
+     */
+    static <T> ModeledFramework<T> wrap(CuratorFramework client, ModelSpec<T> model)
+    {
+        return builder(client, model).build();
+    }
+
+    /**
+     * Start a new ModeledFrameworkBuilder for the given model
+     *
+     * @param client Curator client
+     * @param model the model
+     * @return builder
+     */
+    static <T> ModeledFrameworkBuilder<T> builder(CuratorFramework client, ModelSpec<T> model)
+    {
+        return new ModeledFrameworkBuilder<>(client, model);
+    }
+
+    /**
+     * Start a new ModeledFrameworkBuilder. A client and model must be provided prior to the instance
+     * being built via {@link org.apache.curator.x.async.modeled.ModeledFrameworkBuilder#withClient(org.apache.curator.framework.CuratorFramework)}
+     * and {@link org.apache.curator.x.async.modeled.ModeledFrameworkBuilder#withModelSpec(ModelSpec)}
+     *
+     * @return builder
+     */
+    static <T> ModeledFrameworkBuilder<T> builder()
+    {
+        return new ModeledFrameworkBuilder<>();
+    }
+
+    /**
+     * Use an internally created cache as a front for this modeled instance. All read APIs check the cache
+     * first and, if available, return the values from the cache. Note: you must call
+     * {@link org.apache.curator.x.async.modeled.cached.CachedModeledFramework#start()} and
+     * {@link org.apache.curator.x.async.modeled.cached.CachedModeledFramework#close()} to start/stop
+     *
+     * @return wrapped instance
+     */
+    CachedModeledFramework<T> cached();
+
+    /**
+     * Returns the client that was originally passed to {@link #wrap(org.apache.curator.framework.CuratorFramework, ModelSpec)} or
+     * the builder.
+     *
+     * @return original client
+     */
+    CuratorFramework unwrap();
+
+    /**
+     * Return the model being used
+     *
+     * @return model
+     */
+    ModelSpec<T> modelSpec();
+
+    /**
+     * Return a new Modeled Curator instance with all the same options but applying to the given child node of this Modeled Curator's
+     * path. E.g. if this Modeled Curator instance applies to "/a/b", calling <code>modeled.at("c")</code> returns an instance that applies to
+     * "/a/b/c".
+     *
+     * @param child child node.
+     * @return new Modeled Curator instance
+     */
+    ModeledFramework<T> at(String child);
+
+    /**
+     * Return a Modeled Curator instance with all the same options but using the given path.
+     *
+     * @param path new path
+     * @return new Modeled Curator instance
+     */
+    ModeledFramework<T> at(ZPath path);
+
+    /**
+     * Return a new Modeled Curator instance with all the same options but using the
+     * {@link ModelSpecBuilder#nodeName} functor
+     * to generate the child node's name
+     *
+     * @param model model to use to generate the name
+     * @return new Modeled Curator instance
+     */
+    ModeledFramework<T> resolved(T model);
+
+    /**
+     * Create (or update depending on build options) a ZNode at this instance's path with a serialized
+     * version of the given model
+     *
+     * @param model model to write
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<String> set(T model);
+
+    /**
+     * Create (or update depending on build options) a ZNode at this instance's path with a serialized
+     * form of the given model
+     *
+     * @param model model to write
+     * @param storingStatIn the stat for the new ZNode is stored here
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<String> set(T model, Stat storingStatIn);
+
+    /**
+     * Read the ZNode at this instance's path and deserialize into a model
+     *
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<T> read();
+
+    /**
+     * Read the ZNode at this instance's path and deserialize into a model
+     *
+     * @param storingStatIn the stat for the new ZNode is stored here
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<T> read(Stat storingStatIn);
+
+    /**
+     * Update the ZNode at this instance's path with a serialized
+     * form of the given model passing "-1" for the update version
+     *
+     * @param model model to write
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<Stat> update(T model);
+
+    /**
+     * Update the ZNode at this instance's path with a serialized
+     * form of the given model passing the given update version
+     *
+     * @param model model to write
+     * @param version update version to use
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<Stat> update(T model, int version);
+
+    /**
+     * Delete the ZNode at this instance's path passing -1 for the delete version
+     *
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<Void> delete();
+
+    /**
+     * Delete the ZNode at this instance's path passing the given delete version
+     *
+     * @param version update version to use
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<Void> delete(int version);
+
+    /**
+     * Check to see if the ZNode at this instance's path exists
+     *
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<Stat> checkExists();
+
+    /**
+     * Return the child paths of this instance's path (in no particular order)
+     *
+     * @return AsyncStage
+     * @see org.apache.curator.x.async.AsyncStage
+     */
+    AsyncStage<List<ZPath>> children();
+
+    /**
+     * Create operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction. Note:
+     * due to ZooKeeper transaction limits, this is a _not_ a "set or update" operation but only
+     * a create operation and will generate an error if the node already exists.
+     *
+     * @param model the model
+     * @return operation
+     */
+    CuratorOp createOp(T model);
+
+    /**
+     * Update operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
+     *
+     * @param model the model
+     * @return operation
+     */
+    CuratorOp updateOp(T model);
+
+    /**
+     * Create operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
+     *
+     * @param model the model
+     * @param version update version to use
+     * @return operation
+     */
+    CuratorOp updateOp(T model, int version);
+
+    /**
+     * Delete operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
+     *
+     * @return operation
+     */
+    CuratorOp deleteOp();
+
+    /**
+     * Delete operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
+     *
+     * @param version delete version to use
+     * @return operation
+     */
+    CuratorOp deleteOp(int version);
+
+    /**
+     * Check exists operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
+     *
+     * @return operation
+     */
+    CuratorOp checkExistsOp();
+
+    /**
+     * Check exists operation instance that can be passed among other operations to
+     * {@link #inTransaction(java.util.List)} to be executed as a single transaction.
+     *
+     * @param version version to use
+     * @return operation
+     */
+    CuratorOp checkExistsOp(int version);
+
+    /**
+     * Invoke ZooKeeper to commit the given operations as a single transaction.
+     *
+     * @param operations operations that make up the transaction.
+     * @return AsyncStage instance for managing the completion
+     */
+    AsyncStage<List<CuratorTransactionResult>> inTransaction(List<CuratorOp> operations);
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFrameworkBuilder.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFrameworkBuilder.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFrameworkBuilder.java
new file mode 100644
index 0000000..d2c31b6
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledFrameworkBuilder.java
@@ -0,0 +1,154 @@
+/**
+ * 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.curator.x.async.modeled;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.CuratorEvent;
+import org.apache.curator.framework.api.UnhandledErrorListener;
+import org.apache.curator.x.async.WatchMode;
+import org.apache.curator.x.async.modeled.details.ModeledFrameworkImpl;
+import org.apache.zookeeper.WatchedEvent;
+import java.util.Objects;
+import java.util.function.UnaryOperator;
+
+public class ModeledFrameworkBuilder<T>
+{
+    private CuratorFramework client;
+    private ModelSpec<T> modelSpec;
+    private WatchMode watchMode;
+    private UnaryOperator<WatchedEvent> watcherFilter;
+    private UnhandledErrorListener unhandledErrorListener;
+    private UnaryOperator<CuratorEvent> resultFilter;
+
+    /**
+     * Build a new ModeledFramework instance
+     *
+     * @return new ModeledFramework instance
+     */
+    public ModeledFramework<T> build()
+    {
+        return ModeledFrameworkImpl.build(
+            client,
+            modelSpec,
+            watchMode,
+            watcherFilter,
+            unhandledErrorListener,
+            resultFilter
+        );
+    }
+
+    /**
+     * Add watchers as appropriate to the Modeled Curator's ZNode using
+     * {@link org.apache.curator.x.async.WatchMode#stateChangeAndSuccess}
+     *
+     * @return this for chaining
+     * @see org.apache.curator.x.async.AsyncStage#event()
+     */
+    public ModeledFrameworkBuilder<T> watched()
+    {
+        this.watchMode = WatchMode.stateChangeAndSuccess;
+        return this;
+    }
+
+    /**
+     * Add watchers as appropriate using the given watchMode to the Modeled Curator's ZNode
+     *
+     * @param watchMode watcher style
+     * @return this for chaining
+     * @see org.apache.curator.x.async.AsyncStage#event()
+     */
+    public ModeledFrameworkBuilder<T> watched(WatchMode watchMode)
+    {
+        this.watchMode = watchMode;
+        return this;
+    }
+
+    /**
+     * Add watchers as appropriate using the given watchMode and filter to the Modeled Curator's ZNode
+     *
+     * @param watchMode watcher style
+     * @param watcherFilter filter
+     * @return this for chaining
+     * @see org.apache.curator.x.async.AsyncStage#event()
+     */
+    public ModeledFrameworkBuilder<T> watched(WatchMode watchMode, UnaryOperator<WatchedEvent> watcherFilter)
+    {
+        this.watchMode = watchMode;
+        this.watcherFilter = watcherFilter;
+        return this;
+    }
+
+    /**
+     * Use the given unhandledErrorListener for operations on the Modeled Curator's ZNode
+     *
+     * @param unhandledErrorListener listener
+     * @return this for chaining
+     */
+    public ModeledFrameworkBuilder<T> withUnhandledErrorListener(UnhandledErrorListener unhandledErrorListener)
+    {
+        this.unhandledErrorListener = unhandledErrorListener;
+        return this;
+    }
+
+    /**
+     * Use the given result filter for operations on the Modeled Curator's ZNode
+     *
+     * @param resultFilter filter
+     * @return this for chaining
+     */
+    public ModeledFrameworkBuilder<T> withResultFilter(UnaryOperator<CuratorEvent> resultFilter)
+    {
+        this.resultFilter = resultFilter;
+        return this;
+    }
+
+    /**
+     * Change the model spec to use
+     *
+     * @param modelSpec model spec
+     * @return this for chaining
+     */
+    public ModeledFrameworkBuilder<T> withModelSpec(ModelSpec<T> modelSpec)
+    {
+        this.modelSpec = Objects.requireNonNull(modelSpec, "modelSpec cannot be null");
+        return this;
+    }
+
+    /**
+     * Change the client to use
+     *
+     * @param client new client
+     * @return this for chaining
+     */
+    public ModeledFrameworkBuilder<T> withClient(CuratorFramework client)
+    {
+        this.client = Objects.requireNonNull(client, "client cannot be null");
+        return this;
+    }
+
+    ModeledFrameworkBuilder()
+    {
+    }
+
+    ModeledFrameworkBuilder(CuratorFramework client, ModelSpec<T> modelSpec)
+    {
+        this.client = Objects.requireNonNull(client, "client cannot be null");
+        this.modelSpec = Objects.requireNonNull(modelSpec, "modelSpec cannot be null");
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/NodeName.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/NodeName.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/NodeName.java
new file mode 100644
index 0000000..7dc8340
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/NodeName.java
@@ -0,0 +1,16 @@
+package org.apache.curator.x.async.modeled;
+
+@FunctionalInterface
+public interface NodeName
+{
+    String nodeName();
+
+    static String nameFrom(Object obj)
+    {
+        if ( obj instanceof NodeName )
+        {
+            return ((NodeName)obj).nodeName();
+        }
+        return String.valueOf(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledCuratorFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledCuratorFramework.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledCuratorFramework.java
deleted file mode 100644
index 9f417dd..0000000
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledCuratorFramework.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * 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.curator.x.async.modeled.cached;
-
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
-import org.apache.curator.x.async.modeled.ZPath;
-import java.io.Closeable;
-
-public interface CachedModeledCuratorFramework<T> extends ModeledCuratorFramework<T>, Closeable
-{
-    /**
-     * Return the cache instance
-     *
-     * @return cache
-     */
-    ModeledCache<T> getCache();
-
-    /**
-     * Start the internally created via {@link #cached()}
-     */
-    void start();
-
-    /**
-     * Close the internally created via {@link #cached()}
-     */
-    @Override
-    void close();
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    CachedModeledCuratorFramework<T> at(String child);
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    CachedModeledCuratorFramework<T> at(ZPath path);
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    CachedModeledCuratorFramework<T> resolved(T model);
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledFramework.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledFramework.java
new file mode 100644
index 0000000..a73b0c5
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/cached/CachedModeledFramework.java
@@ -0,0 +1,62 @@
+/**
+ * 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.curator.x.async.modeled.cached;
+
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ZPath;
+import java.io.Closeable;
+
+public interface CachedModeledFramework<T> extends ModeledFramework<T>, Closeable
+{
+    /**
+     * Return the cache instance
+     *
+     * @return cache
+     */
+    ModeledCache<T> getCache();
+
+    /**
+     * Start the internally created via {@link #cached()}
+     */
+    void start();
+
+    /**
+     * Close the internally created via {@link #cached()}
+     */
+    @Override
+    void close();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    CachedModeledFramework<T> at(String child);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    CachedModeledFramework<T> at(ZPath path);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    CachedModeledFramework<T> resolved(T model);
+}


[2/9] curator git commit: CURATOR-401: Make InterProcessMutex.isOwnedByCurrentThread public

Posted by ra...@apache.org.
CURATOR-401: Make InterProcessMutex.isOwnedByCurrentThread public


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/96cb3374
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/96cb3374
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/96cb3374

Branch: refs/heads/CURATOR-397
Commit: 96cb3374f1170afd1b3a5f7ac0fe82d79636a093
Parents: 302661a
Author: Stig Rohde Døssing <st...@gmail.com>
Authored: Tue Apr 18 18:24:56 2017 +0200
Committer: Stig Rohde Døssing <st...@gmail.com>
Committed: Tue Apr 18 18:24:56 2017 +0200

----------------------------------------------------------------------
 .../curator/framework/recipes/locks/InterProcessMutex.java    | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/96cb3374/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessMutex.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessMutex.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessMutex.java
index e178f73..08b8ba1 100644
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessMutex.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/locks/InterProcessMutex.java
@@ -195,7 +195,12 @@ public class InterProcessMutex implements InterProcessLock, Revocable<InterProce
         internals = new LockInternals(client, driver, path, lockName, maxLeases);
     }
 
-    boolean isOwnedByCurrentThread()
+    /**
+     * Returns true if the mutex is acquired by the calling thread
+     * 
+     * @return true/false
+     */
+    public boolean isOwnedByCurrentThread()
     {
         LockData lockData = threadData.get(Thread.currentThread());
         return (lockData != null) && (lockData.lockCount.get() > 0);


[3/9] curator git commit: Merge branch 'CURATOR-401'

Posted by ra...@apache.org.
Merge branch 'CURATOR-401'


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/e8c27f16
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/e8c27f16
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/e8c27f16

Branch: refs/heads/CURATOR-397
Commit: e8c27f162f6610c2c5447ee416251aef41fd4112
Parents: 302661a 96cb337
Author: Fangmin Lyu <fa...@apache.org>
Authored: Mon Apr 24 19:50:16 2017 -0700
Committer: Fangmin Lyu <fa...@apache.org>
Committed: Mon Apr 24 19:50:16 2017 -0700

----------------------------------------------------------------------
 .../curator/framework/recipes/locks/InterProcessMutex.java    | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------



[5/9] curator git commit: CURATOR-3.0 becomes the master branch.

Posted by ra...@apache.org.
CURATOR-3.0 becomes the master branch.


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/ed3082ec
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/ed3082ec
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/ed3082ec

Branch: refs/heads/CURATOR-397
Commit: ed3082ecfebc332ba96da7a5bda4508a1985db6e
Parents: 35f5d27 abaabb5
Author: Scott Blum <dr...@apache.org>
Authored: Tue May 2 15:31:17 2017 -0400
Committer: Scott Blum <dr...@apache.org>
Committed: Tue May 2 15:31:17 2017 -0400

----------------------------------------------------------------------
 .../recipes/locks/InterProcessMutex.java        |  7 +++-
 .../framework/recipes/nodes/PersistentNode.java | 42 +++++++++++++++++++-
 .../recipes/nodes/PersistentNodeListener.java   | 33 +++++++++++++++
 3 files changed, 79 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/ed3082ec/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java
----------------------------------------------------------------------


[6/9] curator git commit: Merge branch 'master' into CURATOR-397

Posted by ra...@apache.org.
Merge branch 'master' into CURATOR-397


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/26c7adbb
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/26c7adbb
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/26c7adbb

Branch: refs/heads/CURATOR-397
Commit: 26c7adbb04a8c20a7d04111253c82ddef28e4f26
Parents: ef9df2b ed3082e
Author: randgalt <ra...@apache.org>
Authored: Tue May 2 15:27:27 2017 -0500
Committer: randgalt <ra...@apache.org>
Committed: Tue May 2 15:27:27 2017 -0500

----------------------------------------------------------------------
 .../recipes/locks/InterProcessMutex.java        |  7 +++-
 .../framework/recipes/nodes/PersistentNode.java | 42 +++++++++++++++++++-
 .../recipes/nodes/PersistentNodeListener.java   | 33 +++++++++++++++
 3 files changed, 79 insertions(+), 3 deletions(-)
----------------------------------------------------------------------



[8/9] curator git commit: Working on strongly typed parameters plus an example that uses it

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledCuratorFrameworkImpl.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledCuratorFrameworkImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledCuratorFrameworkImpl.java
deleted file mode 100644
index a48b9bb..0000000
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledCuratorFrameworkImpl.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
- * 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.curator.x.async.modeled.details;
-
-import com.google.common.collect.Lists;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.api.transaction.CuratorOp;
-import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
-import org.apache.curator.x.async.AsyncStage;
-import org.apache.curator.x.async.api.CreateOption;
-import org.apache.curator.x.async.modeled.ModelSpec;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
-import org.apache.curator.x.async.modeled.cached.ZNode;
-import org.apache.curator.x.async.modeled.ZPath;
-import org.apache.curator.x.async.modeled.cached.CachedModeledCuratorFramework;
-import org.apache.curator.x.async.modeled.cached.ModeledCache;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.data.Stat;
-import org.apache.zookeeper.server.DataTree;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-class CachedModeledCuratorFrameworkImpl<T> implements CachedModeledCuratorFramework<T>
-{
-    private final ModeledCuratorFramework<T> client;
-    private final ModeledCacheImpl<T> cache;
-
-    CachedModeledCuratorFrameworkImpl(ModeledCuratorFramework<T> client)
-    {
-        this(client, new ModeledCacheImpl<>(client.unwrap(), client.modelSpec().path(), client.modelSpec().serializer(), client.modelSpec().createOptions().contains(CreateOption.compress)));
-    }
-
-    private CachedModeledCuratorFrameworkImpl(ModeledCuratorFramework<T> client, ModeledCacheImpl<T> cache)
-    {
-        this.client = client;
-        this.cache = cache;
-    }
-
-    @Override
-    public ModeledCache<T> getCache()
-    {
-        return cache;
-    }
-
-    @Override
-    public void start()
-    {
-        cache.start();
-    }
-
-    @Override
-    public void close()
-    {
-        cache.close();
-    }
-
-    @Override
-    public CachedModeledCuratorFramework<T> cached()
-    {
-        return this;
-    }
-
-    @Override
-    public CuratorFramework unwrap()
-    {
-        return client.unwrap();
-    }
-
-    @Override
-    public ModelSpec<T> modelSpec()
-    {
-        return client.modelSpec();
-    }
-
-    @Override
-    public CachedModeledCuratorFramework<T> at(String child)
-    {
-        return new CachedModeledCuratorFrameworkImpl<>(client.at(child), cache);
-    }
-
-    @Override
-    public CachedModeledCuratorFramework<T> at(ZPath path)
-    {
-        return new CachedModeledCuratorFrameworkImpl<>(client.at(path), cache);
-    }
-
-    @Override
-    public CachedModeledCuratorFramework<T> resolved(T model)
-    {
-        return new CachedModeledCuratorFrameworkImpl<>(client.resolved(model), cache);
-    }
-
-    @Override
-    public AsyncStage<String> set(T model)
-    {
-        return client.set(model);
-    }
-
-    @Override
-    public AsyncStage<String> set(T model, Stat storingStatIn)
-    {
-        return client.set(model, storingStatIn);
-    }
-
-    @Override
-    public AsyncStage<T> read()
-    {
-        return read(null);
-    }
-
-    @Override
-    public AsyncStage<T> read(Stat storingStatIn)
-    {
-        ZPath path = client.modelSpec().path();
-        Optional<ZNode<T>> data = cache.currentData(path);
-        return data.map(node -> {
-            if ( storingStatIn != null )
-            {
-                DataTree.copyStat(node.stat(), storingStatIn);
-            }
-            return new ModelStage<>(node.model());
-        }).orElseGet(() -> new ModelStage<>(new KeeperException.NoNodeException(path.fullPath())));
-    }
-
-    @Override
-    public AsyncStage<Stat> update(T model)
-    {
-        return client.update(model);
-    }
-
-    @Override
-    public AsyncStage<Stat> update(T model, int version)
-    {
-        return client.update(model, version);
-    }
-
-    @Override
-    public AsyncStage<Void> delete()
-    {
-        return client.delete();
-    }
-
-    @Override
-    public AsyncStage<Void> delete(int version)
-    {
-        return client.delete(version);
-    }
-
-    @Override
-    public AsyncStage<Stat> checkExists()
-    {
-        ZPath path = client.modelSpec().path();
-        Optional<ZNode<T>> data = cache.currentData(path);
-        return data.map(node -> new ModelStage<>(node.stat())).orElseGet(() -> new ModelStage<>((Stat)null));
-    }
-
-    @Override
-    public AsyncStage<List<ZPath>> children()
-    {
-        Set<ZPath> paths = cache.currentChildren(client.modelSpec().path()).keySet();
-        return new ModelStage<>(Lists.newArrayList(paths));
-    }
-
-    @Override
-    public CuratorOp createOp(T model)
-    {
-        return client.createOp(model);
-    }
-
-    @Override
-    public CuratorOp updateOp(T model)
-    {
-        return client.updateOp(model);
-    }
-
-    @Override
-    public CuratorOp updateOp(T model, int version)
-    {
-        return client.updateOp(model, version);
-    }
-
-    @Override
-    public CuratorOp deleteOp()
-    {
-        return client.deleteOp();
-    }
-
-    @Override
-    public CuratorOp deleteOp(int version)
-    {
-        return client.deleteOp(version);
-    }
-
-    @Override
-    public CuratorOp checkExistsOp()
-    {
-        return client.checkExistsOp();
-    }
-
-    @Override
-    public CuratorOp checkExistsOp(int version)
-    {
-        return client.checkExistsOp(version);
-    }
-
-    @Override
-    public AsyncStage<List<CuratorTransactionResult>> inTransaction(List<CuratorOp> operations)
-    {
-        return client.inTransaction(operations);
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledFrameworkImpl.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledFrameworkImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledFrameworkImpl.java
new file mode 100644
index 0000000..2f375a9
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/CachedModeledFrameworkImpl.java
@@ -0,0 +1,228 @@
+/**
+ * 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.curator.x.async.modeled.details;
+
+import com.google.common.collect.Lists;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.transaction.CuratorOp;
+import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
+import org.apache.curator.x.async.AsyncStage;
+import org.apache.curator.x.async.api.CreateOption;
+import org.apache.curator.x.async.modeled.ModelSpec;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.cached.ZNode;
+import org.apache.curator.x.async.modeled.ZPath;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import org.apache.curator.x.async.modeled.cached.ModeledCache;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.server.DataTree;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+class CachedModeledFrameworkImpl<T> implements CachedModeledFramework<T>
+{
+    private final ModeledFramework<T> client;
+    private final ModeledCacheImpl<T> cache;
+
+    CachedModeledFrameworkImpl(ModeledFramework<T> client)
+    {
+        this(client, new ModeledCacheImpl<>(client.unwrap(), client.modelSpec().path(), client.modelSpec().serializer(), client.modelSpec().createOptions().contains(CreateOption.compress)));
+    }
+
+    private CachedModeledFrameworkImpl(ModeledFramework<T> client, ModeledCacheImpl<T> cache)
+    {
+        this.client = client;
+        this.cache = cache;
+    }
+
+    @Override
+    public ModeledCache<T> getCache()
+    {
+        return cache;
+    }
+
+    @Override
+    public void start()
+    {
+        cache.start();
+    }
+
+    @Override
+    public void close()
+    {
+        cache.close();
+    }
+
+    @Override
+    public CachedModeledFramework<T> cached()
+    {
+        return this;
+    }
+
+    @Override
+    public CuratorFramework unwrap()
+    {
+        return client.unwrap();
+    }
+
+    @Override
+    public ModelSpec<T> modelSpec()
+    {
+        return client.modelSpec();
+    }
+
+    @Override
+    public CachedModeledFramework<T> at(String child)
+    {
+        return new CachedModeledFrameworkImpl<>(client.at(child), cache);
+    }
+
+    @Override
+    public CachedModeledFramework<T> at(ZPath path)
+    {
+        return new CachedModeledFrameworkImpl<>(client.at(path), cache);
+    }
+
+    @Override
+    public CachedModeledFramework<T> resolved(T model)
+    {
+        return new CachedModeledFrameworkImpl<>(client.resolved(model), cache);
+    }
+
+    @Override
+    public AsyncStage<String> set(T model)
+    {
+        return client.set(model);
+    }
+
+    @Override
+    public AsyncStage<String> set(T model, Stat storingStatIn)
+    {
+        return client.set(model, storingStatIn);
+    }
+
+    @Override
+    public AsyncStage<T> read()
+    {
+        return read(null);
+    }
+
+    @Override
+    public AsyncStage<T> read(Stat storingStatIn)
+    {
+        ZPath path = client.modelSpec().path();
+        Optional<ZNode<T>> data = cache.currentData(path);
+        return data.map(node -> {
+            if ( storingStatIn != null )
+            {
+                DataTree.copyStat(node.stat(), storingStatIn);
+            }
+            return new ModelStage<>(node.model());
+        }).orElseGet(() -> new ModelStage<>(new KeeperException.NoNodeException(path.fullPath())));
+    }
+
+    @Override
+    public AsyncStage<Stat> update(T model)
+    {
+        return client.update(model);
+    }
+
+    @Override
+    public AsyncStage<Stat> update(T model, int version)
+    {
+        return client.update(model, version);
+    }
+
+    @Override
+    public AsyncStage<Void> delete()
+    {
+        return client.delete();
+    }
+
+    @Override
+    public AsyncStage<Void> delete(int version)
+    {
+        return client.delete(version);
+    }
+
+    @Override
+    public AsyncStage<Stat> checkExists()
+    {
+        ZPath path = client.modelSpec().path();
+        Optional<ZNode<T>> data = cache.currentData(path);
+        return data.map(node -> new ModelStage<>(node.stat())).orElseGet(() -> new ModelStage<>((Stat)null));
+    }
+
+    @Override
+    public AsyncStage<List<ZPath>> children()
+    {
+        Set<ZPath> paths = cache.currentChildren(client.modelSpec().path()).keySet();
+        return new ModelStage<>(Lists.newArrayList(paths));
+    }
+
+    @Override
+    public CuratorOp createOp(T model)
+    {
+        return client.createOp(model);
+    }
+
+    @Override
+    public CuratorOp updateOp(T model)
+    {
+        return client.updateOp(model);
+    }
+
+    @Override
+    public CuratorOp updateOp(T model, int version)
+    {
+        return client.updateOp(model, version);
+    }
+
+    @Override
+    public CuratorOp deleteOp()
+    {
+        return client.deleteOp();
+    }
+
+    @Override
+    public CuratorOp deleteOp(int version)
+    {
+        return client.deleteOp(version);
+    }
+
+    @Override
+    public CuratorOp checkExistsOp()
+    {
+        return client.checkExistsOp();
+    }
+
+    @Override
+    public CuratorOp checkExistsOp(int version)
+    {
+        return client.checkExistsOp(version);
+    }
+
+    @Override
+    public AsyncStage<List<CuratorTransactionResult>> inTransaction(List<CuratorOp> operations)
+    {
+        return client.inTransaction(operations);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModelSpecImpl.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModelSpecImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModelSpecImpl.java
index 1ce7134..fb1b888 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModelSpecImpl.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModelSpecImpl.java
@@ -25,16 +25,16 @@ import org.apache.curator.framework.schema.SchemaValidator;
 import org.apache.curator.framework.schema.SchemaViolation;
 import org.apache.curator.x.async.api.CreateOption;
 import org.apache.curator.x.async.api.DeleteOption;
-import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSerializer;
+import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ZPath;
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.data.ACL;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
 
 public class ModelSpecImpl<T> implements ModelSpec<T>, SchemaValidator
 {
@@ -45,9 +45,8 @@ public class ModelSpecImpl<T> implements ModelSpec<T>, SchemaValidator
     private final Set<CreateOption> createOptions;
     private final Set<DeleteOption> deleteOptions;
     private final AtomicReference<Schema> schema = new AtomicReference<>();
-    private final Function<T, String> nodeName;
 
-    public ModelSpecImpl(ZPath path, ModelSerializer<T> serializer, CreateMode createMode, List<ACL> aclList, Set<CreateOption> createOptions, Set<DeleteOption> deleteOptions, Function<T, String> nodeName)
+    public ModelSpecImpl(ZPath path, ModelSerializer<T> serializer, CreateMode createMode, List<ACL> aclList, Set<CreateOption> createOptions, Set<DeleteOption> deleteOptions)
     {
         this.path = Objects.requireNonNull(path, "path cannot be null");
         this.serializer = Objects.requireNonNull(serializer, "serializer cannot be null");
@@ -55,7 +54,6 @@ public class ModelSpecImpl<T> implements ModelSpec<T>, SchemaValidator
         this.aclList = ImmutableList.copyOf(Objects.requireNonNull(aclList, "aclList cannot be null"));
         this.createOptions = ImmutableSet.copyOf(Objects.requireNonNull(createOptions, "createOptions cannot be null"));
         this.deleteOptions = ImmutableSet.copyOf(Objects.requireNonNull(deleteOptions, "deleteOptions cannot be null"));
-        this.nodeName = Objects.requireNonNull(nodeName, "nodeName cannot be null");
     }
 
     @Override
@@ -67,13 +65,13 @@ public class ModelSpecImpl<T> implements ModelSpec<T>, SchemaValidator
     @Override
     public ModelSpec<T> resolved(T model)
     {
-        return at(path.at(nodeName.apply(model)));
+        return at(path.at(NodeName.nameFrom(model)));
     }
 
     @Override
     public ModelSpec<T> at(ZPath newPath)
     {
-        return new ModelSpecImpl<>(newPath, serializer, createMode, aclList, createOptions, deleteOptions, nodeName);
+        return new ModelSpecImpl<>(newPath, serializer, createMode, aclList, createOptions, deleteOptions);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledCuratorFrameworkImpl.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledCuratorFrameworkImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledCuratorFrameworkImpl.java
deleted file mode 100644
index 202e62f..0000000
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledCuratorFrameworkImpl.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * 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.curator.x.async.modeled.details;
-
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.api.CuratorEvent;
-import org.apache.curator.framework.api.UnhandledErrorListener;
-import org.apache.curator.framework.api.transaction.CuratorOp;
-import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
-import org.apache.curator.x.async.AsyncCuratorFramework;
-import org.apache.curator.x.async.AsyncStage;
-import org.apache.curator.x.async.WatchMode;
-import org.apache.curator.x.async.api.AsyncCuratorFrameworkDsl;
-import org.apache.curator.x.async.api.AsyncPathAndBytesable;
-import org.apache.curator.x.async.api.AsyncPathable;
-import org.apache.curator.x.async.api.AsyncTransactionSetDataBuilder;
-import org.apache.curator.x.async.api.CreateOption;
-import org.apache.curator.x.async.api.WatchableAsyncCuratorFramework;
-import org.apache.curator.x.async.modeled.ModelSpec;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
-import org.apache.curator.x.async.modeled.ZPath;
-import org.apache.curator.x.async.modeled.cached.CachedModeledCuratorFramework;
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.data.ACL;
-import org.apache.zookeeper.data.Stat;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.UnaryOperator;
-import java.util.stream.Collectors;
-
-public class ModeledCuratorFrameworkImpl<T> implements ModeledCuratorFramework<T>
-{
-    private final AsyncCuratorFramework client;
-    private final WatchableAsyncCuratorFramework watchableClient;
-    private final ModelSpec<T> modelSpec;
-    private final WatchMode watchMode;
-    private final UnaryOperator<WatchedEvent> watcherFilter;
-    private final UnhandledErrorListener unhandledErrorListener;
-    private final UnaryOperator<CuratorEvent> resultFilter;
-    private final AsyncCuratorFrameworkDsl dslClient;
-
-    public static <T> ModeledCuratorFrameworkImpl<T> build(CuratorFramework client, ModelSpec<T> model, WatchMode watchMode, UnaryOperator<WatchedEvent> watcherFilter, UnhandledErrorListener unhandledErrorListener, UnaryOperator<CuratorEvent> resultFilter)
-    {
-        boolean localIsWatched = (watchMode != null);
-
-        Objects.requireNonNull(client, "client cannot be null");
-        Objects.requireNonNull(model, "model cannot be null");
-
-        watchMode = (watchMode != null) ? watchMode : WatchMode.stateChangeAndSuccess;
-
-        AsyncCuratorFramework asyncClient = AsyncCuratorFramework.wrap(client);
-        AsyncCuratorFrameworkDsl dslClient = asyncClient.with(watchMode, unhandledErrorListener, resultFilter, watcherFilter);
-        WatchableAsyncCuratorFramework watchableClient = localIsWatched ? dslClient.watched() : dslClient;
-
-        return new ModeledCuratorFrameworkImpl<>(
-            asyncClient,
-            dslClient,
-            watchableClient,
-            model,
-            watchMode,
-            watcherFilter,
-            unhandledErrorListener,
-            resultFilter
-        );
-    }
-
-    private ModeledCuratorFrameworkImpl(AsyncCuratorFramework client, AsyncCuratorFrameworkDsl dslClient, WatchableAsyncCuratorFramework watchableClient, ModelSpec<T> modelSpec, WatchMode watchMode, UnaryOperator<WatchedEvent> watcherFilter, UnhandledErrorListener unhandledErrorListener, UnaryOperator<CuratorEvent> resultFilter)
-    {
-        this.client = client;
-        this.dslClient = dslClient;
-        this.watchableClient = watchableClient;
-        this.modelSpec = modelSpec;
-        this.watchMode = watchMode;
-        this.watcherFilter = watcherFilter;
-        this.unhandledErrorListener = unhandledErrorListener;
-        this.resultFilter = resultFilter;
-    }
-
-    @Override
-    public CachedModeledCuratorFramework<T> cached()
-    {
-        return new CachedModeledCuratorFrameworkImpl<>(this);
-    }
-
-    @Override
-    public ModelSpec<T> modelSpec()
-    {
-        return modelSpec;
-    }
-
-    @Override
-    public CuratorFramework unwrap()
-    {
-        return client.unwrap();
-    }
-
-    @Override
-    public AsyncStage<String> set(T item)
-    {
-        return set(item, null);
-    }
-
-    @Override
-    public AsyncStage<String> set(T item, Stat storingStatIn)
-    {
-        byte[] bytes = modelSpec.serializer().serialize(item);
-        return dslClient.create().withOptions(modelSpec.createOptions(), modelSpec.createMode(), fixAclList(modelSpec.aclList()), storingStatIn).forPath(modelSpec.path().fullPath(), bytes);
-    }
-
-    private List<ACL> fixAclList(List<ACL> aclList)
-    {
-        return (aclList.size() > 0) ? aclList : null;   // workaround for old, bad design. empty list not accepted
-    }
-
-    @Override
-    public AsyncStage<T> read()
-    {
-        return read(null);
-    }
-
-    @Override
-    public AsyncStage<T> read(Stat storingStatIn)
-    {
-        AsyncPathable<AsyncStage<byte[]>> next;
-        if ( isCompressed() )
-        {
-            next = (storingStatIn != null) ? watchableClient.getData().decompressedStoringStatIn(storingStatIn) : watchableClient.getData().decompressed();
-        }
-        else
-        {
-            next = (storingStatIn != null) ? watchableClient.getData().storingStatIn(storingStatIn) : watchableClient.getData();
-        }
-        AsyncStage<byte[]> asyncStage = next.forPath(modelSpec.path().fullPath());
-        ModelStage<T> modelStage = new ModelStage<>(asyncStage.event());
-        asyncStage.whenComplete((value, e) -> {
-            if ( e != null )
-            {
-                modelStage.completeExceptionally(e);
-            }
-            else
-            {
-                try
-                {
-                    modelStage.complete(modelSpec.serializer().deserialize(value));
-                }
-                catch ( Exception deserializeException )
-                {
-                    modelStage.completeExceptionally(deserializeException);
-                }
-            }
-        });
-        return modelStage;
-    }
-
-    @Override
-    public AsyncStage<Stat> update(T item)
-    {
-        return update(item, -1);
-    }
-
-    @Override
-    public AsyncStage<Stat> update(T item, int version)
-    {
-        byte[] bytes = modelSpec.serializer().serialize(item);
-        AsyncPathAndBytesable<AsyncStage<Stat>> next = isCompressed() ? dslClient.setData().compressedWithVersion(version) : dslClient.setData();
-        return next.forPath(modelSpec.path().fullPath(), bytes);
-    }
-
-    @Override
-    public AsyncStage<Stat> checkExists()
-    {
-        return watchableClient.checkExists().forPath(modelSpec.path().fullPath());
-    }
-
-    @Override
-    public AsyncStage<Void> delete()
-    {
-        return delete(-1);
-    }
-
-    @Override
-    public AsyncStage<Void> delete(int version)
-    {
-        return dslClient.delete().withVersion(-1).forPath(modelSpec.path().fullPath());
-    }
-
-    @Override
-    public AsyncStage<List<ZPath>> children()
-    {
-        AsyncStage<List<String>> asyncStage = watchableClient.getChildren().forPath(modelSpec.path().fullPath());
-        ModelStage<List<ZPath>> modelStage = new ModelStage<>(asyncStage.event());
-        asyncStage.whenComplete((children, e) -> {
-            if ( e != null )
-            {
-                modelStage.completeExceptionally(e);
-            }
-            else
-            {
-                modelStage.complete(children.stream().map(child -> modelSpec.path().at(child)).collect(Collectors.toList()));
-            }
-        });
-        return modelStage;
-    }
-
-    @Override
-    public ModeledCuratorFramework<T> at(String child)
-    {
-        ModelSpec<T> newModelSpec = modelSpec.at(child);
-        return new ModeledCuratorFrameworkImpl<>(
-            client,
-            dslClient,
-            watchableClient,
-            newModelSpec,
-            watchMode,
-            watcherFilter,
-            unhandledErrorListener,
-            resultFilter
-        );
-    }
-
-    @Override
-    public ModeledCuratorFramework<T> at(ZPath path)
-    {
-        ModelSpec<T> newModelSpec = modelSpec.at(path);
-        return new ModeledCuratorFrameworkImpl<>(
-            client,
-            dslClient,
-            watchableClient,
-            newModelSpec,
-            watchMode,
-            watcherFilter,
-            unhandledErrorListener,
-            resultFilter
-        );
-    }
-
-    @Override
-    public ModeledCuratorFramework<T> resolved(T model)
-    {
-        ModelSpec<T> newModelSpec = modelSpec.resolved(model);
-        return new ModeledCuratorFrameworkImpl<>(
-            client,
-            dslClient,
-            watchableClient,
-            newModelSpec,
-            watchMode,
-            watcherFilter,
-            unhandledErrorListener,
-            resultFilter
-        );
-    }
-
-    public static boolean isCompressed(Set<CreateOption> createOptions)
-    {
-        return createOptions.contains(CreateOption.compress);
-    }
-
-    @Override
-    public CuratorOp createOp(T model)
-    {
-        return client.transactionOp()
-            .create()
-            .withOptions(modelSpec.createMode(), modelSpec.aclList(), modelSpec.createOptions().contains(CreateOption.compress))
-            .forPath(modelSpec.path().fullPath(), modelSpec.serializer().serialize(model));
-    }
-
-    @Override
-    public CuratorOp updateOp(T model)
-    {
-        return updateOp(model, -1);
-    }
-
-    @Override
-    public CuratorOp updateOp(T model, int version)
-    {
-        AsyncTransactionSetDataBuilder builder = client.transactionOp().setData();
-        if ( isCompressed() )
-        {
-            return builder.withVersionCompressed(version).forPath(modelSpec.path().fullPath(), modelSpec.serializer().serialize(model));
-        }
-        return builder.withVersion(version).forPath(modelSpec.path().fullPath(), modelSpec.serializer().serialize(model));
-    }
-
-    @Override
-    public CuratorOp deleteOp()
-    {
-        return deleteOp(-1);
-    }
-
-    @Override
-    public CuratorOp deleteOp(int version)
-    {
-        return client.transactionOp().delete().withVersion(version).forPath(modelSpec.path().fullPath());
-    }
-
-    @Override
-    public CuratorOp checkExistsOp()
-    {
-        return checkExistsOp(-1);
-    }
-
-    @Override
-    public CuratorOp checkExistsOp(int version)
-    {
-        return client.transactionOp().check().withVersion(version).forPath(modelSpec.path().fullPath());
-    }
-
-    @Override
-    public AsyncStage<List<CuratorTransactionResult>> inTransaction(List<CuratorOp> operations)
-    {
-        return client.transaction().forOperations(operations);
-    }
-
-    private boolean isCompressed()
-    {
-        return modelSpec.createOptions().contains(CreateOption.compress);
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledFrameworkImpl.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledFrameworkImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledFrameworkImpl.java
new file mode 100644
index 0000000..46e88f5
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ModeledFrameworkImpl.java
@@ -0,0 +1,335 @@
+/**
+ * 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.curator.x.async.modeled.details;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.CuratorEvent;
+import org.apache.curator.framework.api.UnhandledErrorListener;
+import org.apache.curator.framework.api.transaction.CuratorOp;
+import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
+import org.apache.curator.x.async.AsyncCuratorFramework;
+import org.apache.curator.x.async.AsyncStage;
+import org.apache.curator.x.async.WatchMode;
+import org.apache.curator.x.async.api.AsyncCuratorFrameworkDsl;
+import org.apache.curator.x.async.api.AsyncPathAndBytesable;
+import org.apache.curator.x.async.api.AsyncPathable;
+import org.apache.curator.x.async.api.AsyncTransactionSetDataBuilder;
+import org.apache.curator.x.async.api.CreateOption;
+import org.apache.curator.x.async.api.WatchableAsyncCuratorFramework;
+import org.apache.curator.x.async.modeled.ModelSpec;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ZPath;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+
+public class ModeledFrameworkImpl<T> implements ModeledFramework<T>
+{
+    private final AsyncCuratorFramework client;
+    private final WatchableAsyncCuratorFramework watchableClient;
+    private final ModelSpec<T> modelSpec;
+    private final WatchMode watchMode;
+    private final UnaryOperator<WatchedEvent> watcherFilter;
+    private final UnhandledErrorListener unhandledErrorListener;
+    private final UnaryOperator<CuratorEvent> resultFilter;
+    private final AsyncCuratorFrameworkDsl dslClient;
+
+    public static <T> ModeledFrameworkImpl<T> build(CuratorFramework client, ModelSpec<T> model, WatchMode watchMode, UnaryOperator<WatchedEvent> watcherFilter, UnhandledErrorListener unhandledErrorListener, UnaryOperator<CuratorEvent> resultFilter)
+    {
+        boolean localIsWatched = (watchMode != null);
+
+        Objects.requireNonNull(client, "client cannot be null");
+        Objects.requireNonNull(model, "model cannot be null");
+
+        watchMode = (watchMode != null) ? watchMode : WatchMode.stateChangeAndSuccess;
+
+        AsyncCuratorFramework asyncClient = AsyncCuratorFramework.wrap(client);
+        AsyncCuratorFrameworkDsl dslClient = asyncClient.with(watchMode, unhandledErrorListener, resultFilter, watcherFilter);
+        WatchableAsyncCuratorFramework watchableClient = localIsWatched ? dslClient.watched() : dslClient;
+
+        return new ModeledFrameworkImpl<>(
+            asyncClient,
+            dslClient,
+            watchableClient,
+            model,
+            watchMode,
+            watcherFilter,
+            unhandledErrorListener,
+            resultFilter
+        );
+    }
+
+    private ModeledFrameworkImpl(AsyncCuratorFramework client, AsyncCuratorFrameworkDsl dslClient, WatchableAsyncCuratorFramework watchableClient, ModelSpec<T> modelSpec, WatchMode watchMode, UnaryOperator<WatchedEvent> watcherFilter, UnhandledErrorListener unhandledErrorListener, UnaryOperator<CuratorEvent> resultFilter)
+    {
+        this.client = client;
+        this.dslClient = dslClient;
+        this.watchableClient = watchableClient;
+        this.modelSpec = modelSpec;
+        this.watchMode = watchMode;
+        this.watcherFilter = watcherFilter;
+        this.unhandledErrorListener = unhandledErrorListener;
+        this.resultFilter = resultFilter;
+    }
+
+    @Override
+    public CachedModeledFramework<T> cached()
+    {
+        return new CachedModeledFrameworkImpl<>(this);
+    }
+
+    @Override
+    public ModelSpec<T> modelSpec()
+    {
+        return modelSpec;
+    }
+
+    @Override
+    public CuratorFramework unwrap()
+    {
+        return client.unwrap();
+    }
+
+    @Override
+    public AsyncStage<String> set(T item)
+    {
+        return set(item, null);
+    }
+
+    @Override
+    public AsyncStage<String> set(T item, Stat storingStatIn)
+    {
+        byte[] bytes = modelSpec.serializer().serialize(item);
+        return dslClient.create().withOptions(modelSpec.createOptions(), modelSpec.createMode(), fixAclList(modelSpec.aclList()), storingStatIn).forPath(modelSpec.path().fullPath(), bytes);
+    }
+
+    private List<ACL> fixAclList(List<ACL> aclList)
+    {
+        return (aclList.size() > 0) ? aclList : null;   // workaround for old, bad design. empty list not accepted
+    }
+
+    @Override
+    public AsyncStage<T> read()
+    {
+        return read(null);
+    }
+
+    @Override
+    public AsyncStage<T> read(Stat storingStatIn)
+    {
+        AsyncPathable<AsyncStage<byte[]>> next;
+        if ( isCompressed() )
+        {
+            next = (storingStatIn != null) ? watchableClient.getData().decompressedStoringStatIn(storingStatIn) : watchableClient.getData().decompressed();
+        }
+        else
+        {
+            next = (storingStatIn != null) ? watchableClient.getData().storingStatIn(storingStatIn) : watchableClient.getData();
+        }
+        AsyncStage<byte[]> asyncStage = next.forPath(modelSpec.path().fullPath());
+        ModelStage<T> modelStage = new ModelStage<>(asyncStage.event());
+        asyncStage.whenComplete((value, e) -> {
+            if ( e != null )
+            {
+                modelStage.completeExceptionally(e);
+            }
+            else
+            {
+                try
+                {
+                    modelStage.complete(modelSpec.serializer().deserialize(value));
+                }
+                catch ( Exception deserializeException )
+                {
+                    modelStage.completeExceptionally(deserializeException);
+                }
+            }
+        });
+        return modelStage;
+    }
+
+    @Override
+    public AsyncStage<Stat> update(T item)
+    {
+        return update(item, -1);
+    }
+
+    @Override
+    public AsyncStage<Stat> update(T item, int version)
+    {
+        byte[] bytes = modelSpec.serializer().serialize(item);
+        AsyncPathAndBytesable<AsyncStage<Stat>> next = isCompressed() ? dslClient.setData().compressedWithVersion(version) : dslClient.setData();
+        return next.forPath(modelSpec.path().fullPath(), bytes);
+    }
+
+    @Override
+    public AsyncStage<Stat> checkExists()
+    {
+        return watchableClient.checkExists().forPath(modelSpec.path().fullPath());
+    }
+
+    @Override
+    public AsyncStage<Void> delete()
+    {
+        return delete(-1);
+    }
+
+    @Override
+    public AsyncStage<Void> delete(int version)
+    {
+        return dslClient.delete().withVersion(-1).forPath(modelSpec.path().fullPath());
+    }
+
+    @Override
+    public AsyncStage<List<ZPath>> children()
+    {
+        AsyncStage<List<String>> asyncStage = watchableClient.getChildren().forPath(modelSpec.path().fullPath());
+        ModelStage<List<ZPath>> modelStage = new ModelStage<>(asyncStage.event());
+        asyncStage.whenComplete((children, e) -> {
+            if ( e != null )
+            {
+                modelStage.completeExceptionally(e);
+            }
+            else
+            {
+                modelStage.complete(children.stream().map(child -> modelSpec.path().at(child)).collect(Collectors.toList()));
+            }
+        });
+        return modelStage;
+    }
+
+    @Override
+    public ModeledFramework<T> at(String child)
+    {
+        ModelSpec<T> newModelSpec = modelSpec.at(child);
+        return new ModeledFrameworkImpl<>(
+            client,
+            dslClient,
+            watchableClient,
+            newModelSpec,
+            watchMode,
+            watcherFilter,
+            unhandledErrorListener,
+            resultFilter
+        );
+    }
+
+    @Override
+    public ModeledFramework<T> at(ZPath path)
+    {
+        ModelSpec<T> newModelSpec = modelSpec.at(path);
+        return new ModeledFrameworkImpl<>(
+            client,
+            dslClient,
+            watchableClient,
+            newModelSpec,
+            watchMode,
+            watcherFilter,
+            unhandledErrorListener,
+            resultFilter
+        );
+    }
+
+    @Override
+    public ModeledFramework<T> resolved(T model)
+    {
+        ModelSpec<T> newModelSpec = modelSpec.resolved(model);
+        return new ModeledFrameworkImpl<>(
+            client,
+            dslClient,
+            watchableClient,
+            newModelSpec,
+            watchMode,
+            watcherFilter,
+            unhandledErrorListener,
+            resultFilter
+        );
+    }
+
+    public static boolean isCompressed(Set<CreateOption> createOptions)
+    {
+        return createOptions.contains(CreateOption.compress);
+    }
+
+    @Override
+    public CuratorOp createOp(T model)
+    {
+        return client.transactionOp()
+            .create()
+            .withOptions(modelSpec.createMode(), modelSpec.aclList(), modelSpec.createOptions().contains(CreateOption.compress))
+            .forPath(modelSpec.path().fullPath(), modelSpec.serializer().serialize(model));
+    }
+
+    @Override
+    public CuratorOp updateOp(T model)
+    {
+        return updateOp(model, -1);
+    }
+
+    @Override
+    public CuratorOp updateOp(T model, int version)
+    {
+        AsyncTransactionSetDataBuilder builder = client.transactionOp().setData();
+        if ( isCompressed() )
+        {
+            return builder.withVersionCompressed(version).forPath(modelSpec.path().fullPath(), modelSpec.serializer().serialize(model));
+        }
+        return builder.withVersion(version).forPath(modelSpec.path().fullPath(), modelSpec.serializer().serialize(model));
+    }
+
+    @Override
+    public CuratorOp deleteOp()
+    {
+        return deleteOp(-1);
+    }
+
+    @Override
+    public CuratorOp deleteOp(int version)
+    {
+        return client.transactionOp().delete().withVersion(version).forPath(modelSpec.path().fullPath());
+    }
+
+    @Override
+    public CuratorOp checkExistsOp()
+    {
+        return checkExistsOp(-1);
+    }
+
+    @Override
+    public CuratorOp checkExistsOp(int version)
+    {
+        return client.transactionOp().check().withVersion(version).forPath(modelSpec.path().fullPath());
+    }
+
+    @Override
+    public AsyncStage<List<CuratorTransactionResult>> inTransaction(List<CuratorOp> operations)
+    {
+        return client.transaction().forOperations(operations);
+    }
+
+    private boolean isCompressed()
+    {
+        return modelSpec.createOptions().contains(CreateOption.compress);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec.java
index 8e0f101..6a61f64 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec<M, P1>
 {
     /**

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec10.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec10.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec10.java
index b31aaa5..e6e8be3 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec10.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec10.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec10<M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec2.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec2.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec2.java
index 19fed0a..b8d36ea 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec2.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec2.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec2<M, P1, P2>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec3.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec3.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec3.java
index 2dc7595..1ee78ff 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec3.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec3.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec3<M, P1, P2, P3>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec4.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec4.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec4.java
index d233be5..f15cf8b 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec4.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec4.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec4<M, P1, P2, P3, P4>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec5.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec5.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec5.java
index 685cf2c..09fe323 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec5.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec5.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec5<M, P1, P2, P3, P4, P5>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec6.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec6.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec6.java
index abe811f..58c0607 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec6.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec6.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec6<M, P1, P2, P3, P4, P5, P6>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec7.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec7.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec7.java
index a4e6fdd..2232a88 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec7.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec7.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec7<M, P1, P2, P3, P4, P5, P6, P7>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec8.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec8.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec8.java
index 52b2cb4..b99de07 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec8.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec8.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec8<M, P1, P2, P3, P4, P5, P6, P7, P8>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec9.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec9.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec9.java
index a1ab075..358e31b 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec9.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModelSpec9.java
@@ -3,6 +3,7 @@ package org.apache.curator.x.async.modeled.typed;
 import org.apache.curator.x.async.modeled.ModelSpec;
 import org.apache.curator.x.async.modeled.ModelSpecBuilder;
 
+@FunctionalInterface
 public interface TypedModelSpec9<M, P1, P2, P3, P4, P5, P6, P7, P8, P9>
 {
     ModelSpec<M> resolved(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9);

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework.java
new file mode 100644
index 0000000..3e14240
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework.java
@@ -0,0 +1,32 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework<M, P1>
+{
+    /**
+     * Resolve into a ModeledFramework using the given parameter
+     *
+     * @param client the curator instance to use
+     * @param p1 the parameter
+     * @return ZPath
+     */
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1> TypedModeledFramework<M, P1> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec<M, P1> modelSpec)
+    {
+        return (client, p1) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework10.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework10.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework10.java
new file mode 100644
index 0000000..c5f6bdc
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework10.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework10<M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10> TypedModeledFramework10<M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec10<M, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10> modelSpec)
+    {
+        return (client, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework2.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework2.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework2.java
new file mode 100644
index 0000000..596a869
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework2.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework2<M, P1, P2>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2> TypedModeledFramework2<M, P1, P2> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec2<M, P1, P2> modelSpec)
+    {
+        return (client, p1, p2) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework3.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework3.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework3.java
new file mode 100644
index 0000000..647238d
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework3.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework3<M, P1, P2, P3>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3> TypedModeledFramework3<M, P1, P2, P3> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec3<M, P1, P2, P3> modelSpec)
+    {
+        return (client, p1, p2, p3) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework4.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework4.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework4.java
new file mode 100644
index 0000000..5f9a069
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework4.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework4<M, P1, P2, P3, P4>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4> TypedModeledFramework4<M, P1, P2, P3, P4> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec4<M, P1, P2, P3, P4> modelSpec)
+    {
+        return (client, p1, p2, p3, p4) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework5.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework5.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework5.java
new file mode 100644
index 0000000..723e65a
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework5.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework5<M, P1, P2, P3, P4, P5>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4, P5> TypedModeledFramework5<M, P1, P2, P3, P4, P5> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec5<M, P1, P2, P3, P4, P5> modelSpec)
+    {
+        return (client, p1, p2, p3, p4, p5) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4, p5)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework6.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework6.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework6.java
new file mode 100644
index 0000000..2dea518
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework6.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework6<M, P1, P2, P3, P4, P5, P6>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4, P5, P6> TypedModeledFramework6<M, P1, P2, P3, P4, P5, P6> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec6<M, P1, P2, P3, P4, P5, P6> modelSpec)
+    {
+        return (client, p1, p2, p3, p4, p5, p6) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4, p5, p6)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework7.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework7.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework7.java
new file mode 100644
index 0000000..19a7e67
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework7.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework7<M, P1, P2, P3, P4, P5, P6, P7>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4, P5, P6, P7> TypedModeledFramework7<M, P1, P2, P3, P4, P5, P6, P7> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec7<M, P1, P2, P3, P4, P5, P6, P7> modelSpec)
+    {
+        return (client, p1, p2, p3, p4, p5, p6, p7) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4, p5, p6, p7)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework8.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework8.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework8.java
new file mode 100644
index 0000000..50dc248
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework8.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework8<M, P1, P2, P3, P4, P5, P6, P7, P8>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4, P5, P6, P7, P8> TypedModeledFramework8<M, P1, P2, P3, P4, P5, P6, P7, P8> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec8<M, P1, P2, P3, P4, P5, P6, P7, P8> modelSpec)
+    {
+        return (client, p1, p2, p3, p4, p5, p6, p7, p8) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4, p5, p6, p7, p8)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework9.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework9.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework9.java
new file mode 100644
index 0000000..0a2632c
--- /dev/null
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedModeledFramework9.java
@@ -0,0 +1,25 @@
+package org.apache.curator.x.async.modeled.typed;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ModeledFrameworkBuilder;
+
+@FunctionalInterface
+public interface TypedModeledFramework9<M, P1, P2, P3, P4, P5, P6, P7, P8, P9>
+{
+    ModeledFramework<M> resolved(CuratorFramework client, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9);
+
+    /**
+     * Return a new TypedModeledFramework using the given modeled framework builder and typed model spec.
+     * When {@link #resolved(CuratorFramework, Object, Object, Object, Object, Object, Object, Object, Object, Object)} is called the actual ModeledFramework is generated with the
+     * resolved model spec
+     *
+     * @param frameworkBuilder ModeledFrameworkBuilder
+     * @param modelSpec TypedModelSpec
+     * @return new TypedModeledFramework
+     */
+    static <M, P1, P2, P3, P4, P5, P6, P7, P8, P9> TypedModeledFramework9<M, P1, P2, P3, P4, P5, P6, P7, P8, P9> from(ModeledFrameworkBuilder<M> frameworkBuilder, TypedModelSpec9<M, P1, P2, P3, P4, P5, P6, P7, P8, P9> modelSpec)
+    {
+        return (client, p1, p2, p3, p4, p5, p6, p7, p8, p9) -> frameworkBuilder.withClient(client).withModelSpec(modelSpec.resolved(p1, p2, p3, p4, p5, p6, p7, p8, p9)).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath.java
index 6897980..c76f055 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath.java
@@ -18,6 +18,7 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
@@ -36,6 +37,7 @@ import org.apache.curator.x.async.modeled.ZPath;
  * </pre></code>
  * </p>
  */
+@FunctionalInterface
 public interface TypedZPath<T>
 {
     /**
@@ -65,6 +67,6 @@ public interface TypedZPath<T>
      */
     static <T> TypedZPath<T> from(ZPath path)
     {
-        return path::resolved;
+        return p1 -> path.resolved(NodeName.nameFrom(p1));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath10.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath10.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath10.java
index 2decc50..b289d39 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath10.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath10.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 10 parameters
  */
+@FunctionalInterface
 public interface TypedZPath10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10);
@@ -46,6 +48,6 @@ public interface TypedZPath10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
      */
     static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> TypedZPath10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4), NodeName.nameFrom(p5), NodeName.nameFrom(p6), NodeName.nameFrom(p7), NodeName.nameFrom(p8), NodeName.nameFrom(p9), NodeName.nameFrom(p10));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath2.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath2.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath2.java
index 23aad80..6cd6cb3 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath2.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath2.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 2 parameters
  */
+@FunctionalInterface
 public interface TypedZPath2<T1, T2>
 {
     ZPath resolved(T1 p1, T2 p2);
@@ -46,6 +48,6 @@ public interface TypedZPath2<T1, T2>
      */
     static <T1, T2> TypedZPath2<T1, T2> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath3.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath3.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath3.java
index a3fd53c..507941e 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath3.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath3.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 3 parameters
  */
+@FunctionalInterface
 public interface TypedZPath3<T1, T2, T3>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3);
@@ -46,6 +48,6 @@ public interface TypedZPath3<T1, T2, T3>
      */
     static <T1, T2, T3> TypedZPath3<T1, T2, T3> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath4.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath4.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath4.java
index 11ac783..1c5a71c 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath4.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath4.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 4 parameters
  */
+@FunctionalInterface
 public interface TypedZPath4<T1, T2, T3, T4>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4);
@@ -46,6 +48,6 @@ public interface TypedZPath4<T1, T2, T3, T4>
      */
     static <T1, T2, T3, T4> TypedZPath4<T1, T2, T3, T4> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath5.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath5.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath5.java
index e238528..e7df047 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath5.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath5.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 5 parameters
  */
+@FunctionalInterface
 public interface TypedZPath5<T1, T2, T3, T4, T5>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5);
@@ -46,6 +48,6 @@ public interface TypedZPath5<T1, T2, T3, T4, T5>
      */
     static <T1, T2, T3, T4, T5> TypedZPath5<T1, T2, T3, T4, T5> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4, p5) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4), NodeName.nameFrom(p5));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath6.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath6.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath6.java
index 956c544..9f0e5a7 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath6.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath6.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 6 parameters
  */
+@FunctionalInterface
 public interface TypedZPath6<T1, T2, T3, T4, T5, T6>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6);
@@ -46,6 +48,6 @@ public interface TypedZPath6<T1, T2, T3, T4, T5, T6>
      */
     static <T1, T2, T3, T4, T5, T6> TypedZPath6<T1, T2, T3, T4, T5, T6> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4, p5, p6) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4), NodeName.nameFrom(p5), NodeName.nameFrom(p6));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath7.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath7.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath7.java
index 9d9acf1..a4298a4 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath7.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath7.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 7 parameters
  */
+@FunctionalInterface
 public interface TypedZPath7<T1, T2, T3, T4, T5, T6, T7>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7);
@@ -46,6 +48,6 @@ public interface TypedZPath7<T1, T2, T3, T4, T5, T6, T7>
      */
     static <T1, T2, T3, T4, T5, T6, T7> TypedZPath7<T1, T2, T3, T4, T5, T6, T7> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4, p5, p6, p7) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4), NodeName.nameFrom(p5), NodeName.nameFrom(p6), NodeName.nameFrom(p7));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath8.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath8.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath8.java
index f6f2a18..0e774fb 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath8.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath8.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 8 parameters
  */
+@FunctionalInterface
 public interface TypedZPath8<T1, T2, T3, T4, T5, T6, T7, T8>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8);
@@ -46,6 +48,6 @@ public interface TypedZPath8<T1, T2, T3, T4, T5, T6, T7, T8>
      */
     static <T1, T2, T3, T4, T5, T6, T7, T8> TypedZPath8<T1, T2, T3, T4, T5, T6, T7, T8> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4, p5, p6, p7, p8) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4), NodeName.nameFrom(p5), NodeName.nameFrom(p6), NodeName.nameFrom(p7), NodeName.nameFrom(p8));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath9.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath9.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath9.java
index 986401a..804574b 100644
--- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath9.java
+++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/typed/TypedZPath9.java
@@ -18,11 +18,13 @@
  */
 package org.apache.curator.x.async.modeled.typed;
 
+import org.apache.curator.x.async.modeled.NodeName;
 import org.apache.curator.x.async.modeled.ZPath;
 
 /**
  * Same as {@link org.apache.curator.x.async.modeled.typed.TypedZPath}, but with 9 parameters
  */
+@FunctionalInterface
 public interface TypedZPath9<T1, T2, T3, T4, T5, T6, T7, T8, T9>
 {
     ZPath resolved(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9);
@@ -46,6 +48,6 @@ public interface TypedZPath9<T1, T2, T3, T4, T5, T6, T7, T8, T9>
      */
     static <T1, T2, T3, T4, T5, T6, T7, T8, T9> TypedZPath9<T1, T2, T3, T4, T5, T6, T7, T8, T9> from(ZPath path)
     {
-        return path::resolved;
+        return (p1, p2, p3, p4, p5, p6, p7, p8, p9) -> path.resolved(NodeName.nameFrom(p1), NodeName.nameFrom(p2), NodeName.nameFrom(p3), NodeName.nameFrom(p4), NodeName.nameFrom(p5), NodeName.nameFrom(p6), NodeName.nameFrom(p7), NodeName.nameFrom(p8), NodeName.nameFrom(p9));
     }
 }

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/site/confluence/index.confluence
----------------------------------------------------------------------
diff --git a/curator-x-async/src/site/confluence/index.confluence b/curator-x-async/src/site/confluence/index.confluence
index 8788b76..576b5da 100644
--- a/curator-x-async/src/site/confluence/index.confluence
+++ b/curator-x-async/src/site/confluence/index.confluence
@@ -38,7 +38,7 @@ opposed to raw byte arrays. For example:
 
 {code}
 // let "client" be a CuratorFramework instance
-ModeledCuratorFramework<MyModel> modeled = ModeledCuratorFramework.wrap(client, path, serializer);
+ModeledFramework<MyModel> modeled = ModeledCuratorFramework.wrap(client, path, serializer);
 modeled.create(new MyModel());
 {code}
 

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/site/confluence/modeled.confluence
----------------------------------------------------------------------
diff --git a/curator-x-async/src/site/confluence/modeled.confluence b/curator-x-async/src/site/confluence/modeled.confluence
index 3623728..8fcddf0 100644
--- a/curator-x-async/src/site/confluence/modeled.confluence
+++ b/curator-x-async/src/site/confluence/modeled.confluence
@@ -5,7 +5,7 @@ opposed to raw byte arrays. For example:
 
 {code}
 // let "client" be a CuratorFramework instance
-ModeledCuratorFramework<MyModel> modeled = ModeledCuratorFramework.wrap(client, path, serializer);
+ModeledFramework<MyModel> modeled = ModeledCuratorFramework.wrap(client, path, serializer);
 modeled.create(new MyModel());
 {code}
 
@@ -35,7 +35,7 @@ ZooKeeper paths.
 
 h4. Building
 
-You build a {{ModeledCuratorFramework}} instance using either the builder or helper wrapper. All
+You build a {{ModeledFramework}} instance using either the builder or helper wrapper. All
 options needed to use the ZPath are specified at build time:
 
 * whether and/or how to watch the ZNode
@@ -45,7 +45,7 @@ options needed to use the ZPath are specified at build time:
 * any ACLs
 * etc.
 
-These options are bound into the {{ModeledCuratorFramework}} instance and applied as needed.
+These options are bound into the {{ModeledFramework}} instance and applied as needed.
 
 h2. Example
 
@@ -75,7 +75,7 @@ public class Person {
 }
 {code}
 
-We can now build a {{ModeledCuratorFramework}} that manages {{Person}} instances at a given path:
+We can now build a {{ModeledFramework}} that manages {{Person}} instances at a given path:
 
 {code}
 // let "client" be a CuratorFramework instance


[4/9] curator git commit: Merge branch 'CURATOR-386'

Posted by ra...@apache.org.
Merge branch 'CURATOR-386'


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/abaabb5f
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/abaabb5f
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/abaabb5f

Branch: refs/heads/CURATOR-397
Commit: abaabb5f65c2161f77527165a15d2420f6c88219
Parents: e8c27f1 bec1443
Author: Fangmin Lyu <fa...@apache.org>
Authored: Mon Apr 24 20:08:58 2017 -0700
Committer: Fangmin Lyu <fa...@apache.org>
Committed: Mon Apr 24 20:08:58 2017 -0700

----------------------------------------------------------------------
 .../framework/recipes/nodes/PersistentNode.java | 42 +++++++++++++++++++-
 .../recipes/nodes/PersistentNodeListener.java   | 33 +++++++++++++++
 2 files changed, 73 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/abaabb5f/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentNode.java
----------------------------------------------------------------------


[7/9] curator git commit: Working on strongly typed parameters plus an example that uses it

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledCuratorFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledCuratorFramework.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledCuratorFramework.java
deleted file mode 100644
index d54ef6f..0000000
--- a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledCuratorFramework.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * 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.curator.x.async.modeled;
-
-import com.google.common.collect.Sets;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.utils.CloseableUtils;
-import org.apache.curator.x.async.AsyncStage;
-import org.apache.curator.x.async.CompletableBaseClassForTests;
-import org.apache.curator.x.async.modeled.models.TestModel;
-import org.apache.curator.x.async.modeled.models.TestNewerModel;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import java.math.BigInteger;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-
-public class TestModeledCuratorFramework extends CompletableBaseClassForTests
-{
-    private static final ZPath path = ZPath.parse("/test/path");
-    private CuratorFramework rawClient;
-    private JacksonModelSerializer<TestModel> serializer;
-    private JacksonModelSerializer<TestNewerModel> newSerializer;
-    private ModelSpec<TestModel> modelSpec;
-    private ModelSpec<TestNewerModel> newModelSpec;
-
-    @BeforeMethod
-    @Override
-    public void setup() throws Exception
-    {
-        super.setup();
-
-        rawClient = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
-        rawClient.start();
-
-        serializer = new JacksonModelSerializer<>(TestModel.class);
-        newSerializer = new JacksonModelSerializer<>(TestNewerModel.class);
-
-        modelSpec = ModelSpec.builder(path, serializer).build();
-        newModelSpec = ModelSpec.builder(path, newSerializer).build();
-    }
-
-    @AfterMethod
-    @Override
-    public void teardown() throws Exception
-    {
-        CloseableUtils.closeQuietly(rawClient);
-        super.teardown();
-    }
-
-    @Test
-    public void testCrud()
-    {
-        TestModel rawModel = new TestModel("John", "Galt", "1 Galt's Gulch", 42, BigInteger.valueOf(1));
-        TestModel rawModel2 = new TestModel("Wayne", "Rooney", "Old Trafford", 10, BigInteger.valueOf(1));
-        ModeledCuratorFramework<TestModel> client = ModeledCuratorFramework.wrap(rawClient, modelSpec);
-        AsyncStage<String> stage = client.set(rawModel);
-        Assert.assertNull(stage.event());
-        complete(stage, (s, e) -> Assert.assertNotNull(s));
-        complete(client.read(), (model, e) -> Assert.assertEquals(model, rawModel));
-        complete(client.update(rawModel2));
-        complete(client.read(), (model, e) -> Assert.assertEquals(model, rawModel2));
-        complete(client.delete());
-        complete(client.checkExists(), (stat, e) -> Assert.assertNull(stat));
-    }
-
-    @Test
-    public void testBackwardCompatibility()
-    {
-        TestNewerModel rawNewModel = new TestNewerModel("John", "Galt", "1 Galt's Gulch", 42, BigInteger.valueOf(1), 100);
-        ModeledCuratorFramework<TestNewerModel> clientForNew = ModeledCuratorFramework.wrap(rawClient, newModelSpec);
-        complete(clientForNew.set(rawNewModel), (s, e) -> Assert.assertNotNull(s));
-
-        ModeledCuratorFramework<TestModel> clientForOld = ModeledCuratorFramework.wrap(rawClient, modelSpec);
-        complete(clientForOld.read(), (model, e) -> Assert.assertTrue(rawNewModel.equalsOld(model)));
-    }
-
-    @Test
-    public void testWatched() throws InterruptedException
-    {
-        CountDownLatch latch = new CountDownLatch(1);
-        ModeledCuratorFramework<TestModel> client = ModeledCuratorFramework.builder(rawClient, modelSpec).watched().build();
-        client.checkExists().event().whenComplete((event, ex) -> latch.countDown());
-        timing.sleepABit();
-        Assert.assertEquals(latch.getCount(), 1);
-        client.set(new TestModel());
-        Assert.assertTrue(timing.awaitLatch(latch));
-    }
-
-    @Test
-    public void testGetChildren()
-    {
-        TestModel model = new TestModel("John", "Galt", "1 Galt's Gulch", 42, BigInteger.valueOf(1));
-        ModeledCuratorFramework<TestModel> client = ModeledCuratorFramework.builder(rawClient, modelSpec).build();
-        complete(client.at("one").set(model));
-        complete(client.at("two").set(model));
-        complete(client.at("three").set(model));
-
-        Set<ZPath> expected = Sets.newHashSet(path.at("one"), path.at("two"), path.at("three"));
-        complete(client.children(), (children, e) -> Assert.assertEquals(Sets.newHashSet(children), expected));
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
new file mode 100644
index 0000000..acca126
--- /dev/null
+++ b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
@@ -0,0 +1,122 @@
+/**
+ * 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.curator.x.async.modeled;
+
+import com.google.common.collect.Sets;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.RetryOneTime;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.curator.x.async.AsyncStage;
+import org.apache.curator.x.async.CompletableBaseClassForTests;
+import org.apache.curator.x.async.modeled.models.TestModel;
+import org.apache.curator.x.async.modeled.models.TestNewerModel;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import java.math.BigInteger;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+public class TestModeledFramework extends CompletableBaseClassForTests
+{
+    private static final ZPath path = ZPath.parse("/test/path");
+    private CuratorFramework rawClient;
+    private JacksonModelSerializer<TestModel> serializer;
+    private JacksonModelSerializer<TestNewerModel> newSerializer;
+    private ModelSpec<TestModel> modelSpec;
+    private ModelSpec<TestNewerModel> newModelSpec;
+
+    @BeforeMethod
+    @Override
+    public void setup() throws Exception
+    {
+        super.setup();
+
+        rawClient = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
+        rawClient.start();
+
+        serializer = new JacksonModelSerializer<>(TestModel.class);
+        newSerializer = new JacksonModelSerializer<>(TestNewerModel.class);
+
+        modelSpec = ModelSpec.builder(path, serializer).build();
+        newModelSpec = ModelSpec.builder(path, newSerializer).build();
+    }
+
+    @AfterMethod
+    @Override
+    public void teardown() throws Exception
+    {
+        CloseableUtils.closeQuietly(rawClient);
+        super.teardown();
+    }
+
+    @Test
+    public void testCrud()
+    {
+        TestModel rawModel = new TestModel("John", "Galt", "1 Galt's Gulch", 42, BigInteger.valueOf(1));
+        TestModel rawModel2 = new TestModel("Wayne", "Rooney", "Old Trafford", 10, BigInteger.valueOf(1));
+        ModeledFramework<TestModel> client = ModeledFramework.wrap(rawClient, modelSpec);
+        AsyncStage<String> stage = client.set(rawModel);
+        Assert.assertNull(stage.event());
+        complete(stage, (s, e) -> Assert.assertNotNull(s));
+        complete(client.read(), (model, e) -> Assert.assertEquals(model, rawModel));
+        complete(client.update(rawModel2));
+        complete(client.read(), (model, e) -> Assert.assertEquals(model, rawModel2));
+        complete(client.delete());
+        complete(client.checkExists(), (stat, e) -> Assert.assertNull(stat));
+    }
+
+    @Test
+    public void testBackwardCompatibility()
+    {
+        TestNewerModel rawNewModel = new TestNewerModel("John", "Galt", "1 Galt's Gulch", 42, BigInteger.valueOf(1), 100);
+        ModeledFramework<TestNewerModel> clientForNew = ModeledFramework.wrap(rawClient, newModelSpec);
+        complete(clientForNew.set(rawNewModel), (s, e) -> Assert.assertNotNull(s));
+
+        ModeledFramework<TestModel> clientForOld = ModeledFramework.wrap(rawClient, modelSpec);
+        complete(clientForOld.read(), (model, e) -> Assert.assertTrue(rawNewModel.equalsOld(model)));
+    }
+
+    @Test
+    public void testWatched() throws InterruptedException
+    {
+        CountDownLatch latch = new CountDownLatch(1);
+        ModeledFramework<TestModel> client = ModeledFramework.builder(rawClient, modelSpec).watched().build();
+        client.checkExists().event().whenComplete((event, ex) -> latch.countDown());
+        timing.sleepABit();
+        Assert.assertEquals(latch.getCount(), 1);
+        client.set(new TestModel());
+        Assert.assertTrue(timing.awaitLatch(latch));
+    }
+
+    @Test
+    public void testGetChildren()
+    {
+        TestModel model = new TestModel("John", "Galt", "1 Galt's Gulch", 42, BigInteger.valueOf(1));
+        ModeledFramework<TestModel> client = ModeledFramework.builder(rawClient, modelSpec).build();
+        complete(client.at("one").set(model));
+        complete(client.at("two").set(model));
+        complete(client.at("three").set(model));
+
+        Set<ZPath> expected = Sets.newHashSet(path.at("one"), path.at("two"), path.at("three"));
+        complete(client.children(), (children, e) -> Assert.assertEquals(Sets.newHashSet(children), expected));
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledCuratorFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledCuratorFramework.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledCuratorFramework.java
deleted file mode 100644
index 1bc3434..0000000
--- a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledCuratorFramework.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * 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.curator.x.async.modeled.details;
-
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.retry.RetryOneTime;
-import org.apache.curator.utils.CloseableUtils;
-import org.apache.curator.x.async.CompletableBaseClassForTests;
-import org.apache.curator.x.async.modeled.cached.CachedModeledCuratorFramework;
-import org.apache.curator.x.async.modeled.ModelSpec;
-import org.apache.curator.x.async.modeled.JacksonModelSerializer;
-import org.apache.curator.x.async.modeled.ModelSerializer;
-import org.apache.curator.x.async.modeled.ModeledCuratorFramework;
-import org.apache.curator.x.async.modeled.ZPath;
-import org.apache.curator.x.async.modeled.models.TestSimpleModel;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class TestCachedModeledCuratorFramework extends CompletableBaseClassForTests
-{
-    private static final ZPath path = ZPath.parse("/test/path");
-    private CuratorFramework rawClient;
-    private CachedModeledCuratorFramework<TestSimpleModel> client;
-
-    @BeforeMethod
-    @Override
-    public void setup() throws Exception
-    {
-        super.setup();
-
-        rawClient = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
-        rawClient.start();
-
-        ModelSerializer<TestSimpleModel> serializer = new JacksonModelSerializer<>(TestSimpleModel.class);
-        client = ModeledCuratorFramework.builder(rawClient, ModelSpec.builder(path, serializer).build()).build().cached();
-    }
-
-    @AfterMethod
-    @Override
-    public void teardown() throws Exception
-    {
-        CloseableUtils.closeQuietly(rawClient);
-        super.teardown();
-    }
-
-    @Test
-    public void testBasic() throws InterruptedException
-    {
-        client.start();
-
-        AtomicInteger counter = new AtomicInteger();
-//        ((CachedModeledCuratorFrameworkImpl)client).debugCachedReadCount = counter;
-
-        complete(client.read());
-        Assert.assertEquals(counter.get(), 0);
-
-        complete(client.set(new TestSimpleModel("test", 10)));
-        Assert.assertEquals(counter.get(), 0);
-
-        timing.sleepABit();
-
-        complete(client.read());
-        Assert.assertEquals(counter.get(), 1);
-        counter.set(0);
-
-        complete(client.set(new TestSimpleModel("test2", 20)));
-        Assert.assertEquals(counter.get(), 0);
-
-        timing.sleepABit();
-
-        complete(client.read(), (model, e) -> Assert.assertEquals(model, new TestSimpleModel("test2", 20)));
-        Assert.assertEquals(counter.get(), 1);
-
-        client.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/1fcb63a5/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledFramework.java
----------------------------------------------------------------------
diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledFramework.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledFramework.java
new file mode 100644
index 0000000..70ef93e
--- /dev/null
+++ b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/details/TestCachedModeledFramework.java
@@ -0,0 +1,96 @@
+/**
+ * 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.curator.x.async.modeled.details;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.RetryOneTime;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.curator.x.async.CompletableBaseClassForTests;
+import org.apache.curator.x.async.modeled.cached.CachedModeledFramework;
+import org.apache.curator.x.async.modeled.ModelSpec;
+import org.apache.curator.x.async.modeled.JacksonModelSerializer;
+import org.apache.curator.x.async.modeled.ModelSerializer;
+import org.apache.curator.x.async.modeled.ModeledFramework;
+import org.apache.curator.x.async.modeled.ZPath;
+import org.apache.curator.x.async.modeled.models.TestSimpleModel;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class TestCachedModeledFramework extends CompletableBaseClassForTests
+{
+    private static final ZPath path = ZPath.parse("/test/path");
+    private CuratorFramework rawClient;
+    private CachedModeledFramework<TestSimpleModel> client;
+
+    @BeforeMethod
+    @Override
+    public void setup() throws Exception
+    {
+        super.setup();
+
+        rawClient = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
+        rawClient.start();
+
+        ModelSerializer<TestSimpleModel> serializer = new JacksonModelSerializer<>(TestSimpleModel.class);
+        client = ModeledFramework.builder(rawClient, ModelSpec.builder(path, serializer).build()).build().cached();
+    }
+
+    @AfterMethod
+    @Override
+    public void teardown() throws Exception
+    {
+        CloseableUtils.closeQuietly(rawClient);
+        super.teardown();
+    }
+
+    @Test
+    public void testBasic() throws InterruptedException
+    {
+        client.start();
+
+        AtomicInteger counter = new AtomicInteger();
+//        ((CachedModeledCuratorFrameworkImpl)client).debugCachedReadCount = counter;
+
+        complete(client.read());
+        Assert.assertEquals(counter.get(), 0);
+
+        complete(client.set(new TestSimpleModel("test", 10)));
+        Assert.assertEquals(counter.get(), 0);
+
+        timing.sleepABit();
+
+        complete(client.read());
+        Assert.assertEquals(counter.get(), 1);
+        counter.set(0);
+
+        complete(client.set(new TestSimpleModel("test2", 20)));
+        Assert.assertEquals(counter.get(), 0);
+
+        timing.sleepABit();
+
+        complete(client.read(), (model, e) -> Assert.assertEquals(model, new TestSimpleModel("test2", 20)));
+        Assert.assertEquals(counter.get(), 1);
+
+        client.close();
+    }
+}