Repository: curator Updated Branches: refs/heads/CURATOR-397 e0a27daef -> aadb72b62
doc Project: http://git-wip-us.apache.org/repos/asf/curator/repo Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/bf43232b Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/bf43232b Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/bf43232b Branch: refs/heads/CURATOR-397 Commit: bf43232bd9f30efa0482203f895e4adb207ab247 Parents: e0a27da Author: randgalt <randg...@apache.org> Authored: Sun Apr 9 08:47:02 2017 -0500 Committer: randgalt <randg...@apache.org> Committed: Sun Apr 9 08:47:02 2017 -0500 ---------------------------------------------------------------------- .../details/recipes/ModeledCachedNodeImpl.java | 11 ++--- .../modeled/recipes/ModeledCacheListener.java | 2 +- .../modeled/recipes/ModeledCachedNode.java | 7 ++- .../src/site/confluence/index.confluence | 18 ++++++- .../confluence/modeled-cache-recipes.confluence | 45 +++++++++++++++++ .../src/site/confluence/modeled.confluence | 2 +- curator-x-async/src/site/site.xml | 2 +- .../modeled/recipes/TestModeledCaches.java | 51 +++++--------------- curator-x-rpc/src/site/site.xml | 2 +- 9 files changed, 84 insertions(+), 56 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/recipes/ModeledCachedNodeImpl.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/recipes/ModeledCachedNodeImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/recipes/ModeledCachedNodeImpl.java index cdf967d..e66fd8a 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/recipes/ModeledCachedNodeImpl.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/recipes/ModeledCachedNodeImpl.java @@ -22,13 +22,12 @@ import org.apache.curator.x.async.modeled.ZPath; import org.apache.curator.x.async.modeled.recipes.ModeledCachedNode; import org.apache.zookeeper.data.Stat; import java.util.Objects; -import java.util.Optional; public class ModeledCachedNodeImpl<T> implements ModeledCachedNode<T> { private final ZPath path; private final Stat stat; - private final Optional<T> data; + private final T data; public ModeledCachedNodeImpl(ZPath path) { @@ -43,8 +42,8 @@ public class ModeledCachedNodeImpl<T> implements ModeledCachedNode<T> public ModeledCachedNodeImpl(ZPath path, T data, Stat stat) { this.path = Objects.requireNonNull(path, "path cannot be null"); - this.data = Optional.ofNullable(data); this.stat = Objects.requireNonNull(stat, "stat cannot be null"); + this.data = data; } @Override @@ -60,7 +59,7 @@ public class ModeledCachedNodeImpl<T> implements ModeledCachedNode<T> } @Override - public Optional<T> getData() + public T getModel() { return data; } @@ -88,7 +87,7 @@ public class ModeledCachedNodeImpl<T> implements ModeledCachedNode<T> { return false; } - return data.equals(that.data); + return data != null ? data.equals(that.data) : that.data == null; } @Override @@ -96,7 +95,7 @@ public class ModeledCachedNodeImpl<T> implements ModeledCachedNode<T> { int result = path.hashCode(); result = 31 * result + stat.hashCode(); - result = 31 * result + data.hashCode(); + result = 31 * result + (data != null ? data.hashCode() : 0); return result; } http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCacheListener.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCacheListener.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCacheListener.java index 8d6d2cc..c3660a9 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCacheListener.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCacheListener.java @@ -79,6 +79,6 @@ public interface ModeledCacheListener<T> */ static <T> Predicate<ModeledCacheEvent<T>> hasModelFilter() { - return event -> event.getNode().isPresent() && event.getNode().get().getData().isPresent(); + return event -> event.getNode().isPresent() && (event.getNode().get().getModel() != null); } } http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCachedNode.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCachedNode.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCachedNode.java index 3808029..a54f7b7 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCachedNode.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/recipes/ModeledCachedNode.java @@ -20,7 +20,6 @@ package org.apache.curator.x.async.modeled.recipes; import org.apache.curator.x.async.modeled.ZPath; import org.apache.zookeeper.data.Stat; -import java.util.Optional; /** * Abstracts a cached node @@ -42,9 +41,9 @@ public interface ModeledCachedNode<T> Stat getStat(); /** - * The node's current data + * The node's current model * - * @return data + * @return model */ - Optional<T> getData(); + T getModel(); } http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/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 3ea8b4c..d192f47 100644 --- a/curator-x-async/src/site/confluence/index.confluence +++ b/curator-x-async/src/site/confluence/index.confluence @@ -15,8 +15,8 @@ and simplified, in particular for operations such as {{create()}}. With this DSL you can do asynchronous tasks in a more natural, functional way using [Java 8 lambdas|https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html]. -The Curator Async package also contains a strongly typed DSL that allows you to map a ZooKeeper path -to a serializable class as opposed to raw byte arrays. +The Curator Async package also contains a strongly typed DSL and strongly typed Cache Recipe wrappers that +allows you to map a ZooKeeper path to a serializable class as opposed to raw byte arrays. h2. [[Curator Async|async.html]] @@ -44,3 +44,17 @@ modeled.create(new MyModel()); See [[Modeled Curator|modeled.html]] for details. +h2. [[Modeled Cache Recipes|modeled-cache-recipes.html]] + +Strongly typed wrappers for Curator's Cache Recipes (NodeCache, PathChildrenCache and TreeCache) allow +you to use serializable classes as opposed to raw byte arrays. For example: + +{code} +ModeledNodeCache<MyModel> cache = ModeledNodeCache.wrap(nodeCache, serializer) +cache.getCurrentData().ifPresent(data -> { + MyModel model = data.getData(); + ... +); +{code} + +See [[Modeled Cache Recipes|modeled-cache-recipes.html]] for details. http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-async/src/site/confluence/modeled-cache-recipes.confluence ---------------------------------------------------------------------- diff --git a/curator-x-async/src/site/confluence/modeled-cache-recipes.confluence b/curator-x-async/src/site/confluence/modeled-cache-recipes.confluence new file mode 100644 index 0000000..ba461df --- /dev/null +++ b/curator-x-async/src/site/confluence/modeled-cache-recipes.confluence @@ -0,0 +1,45 @@ +h1. Modeled Cache Recipes + +Strongly typed wrappers for Curator's Cache Recipes (NodeCache, PathChildrenCache and TreeCache) allow +you to use serializable classes as opposed to raw byte arrays. For example: + +{code} +ModeledNodeCache<MyModel> cache = ModeledNodeCache.wrap(nodeCache, serializer) +cache.getCurrentData().ifPresent(data -> { + MyModel model = data.getData(); + ... +); +{code} + +h2. Usage + +NOTE: the modeled Cache Recipes require Curator's "curator\-recipes" module. However, to +avoid circular dependencies the internal dependency is {{provided}}. Therefore, if you wish to use +the modeled Cache Recipes wrappers you must manually add the "curator\-recipes" dependency to your build +system. + +Any of the Curator Cache Recipes — NodeCache, PathChildrenCache or TreeCache — can be wrapped +with "modeled" versions: {{ModeledNodeCache}}, {{ModeledPathChildrenCache}} and {{ModeledTreeCache}}. +Each wrapper has a {{wrap()}} method that takes an instance of the cache and a serializer. All the +main methods of each cache are duplicated in the wrapper. However, the data object and listeners +are altered to specify typed models via {{ModeledCachedNode<T>}} and {{ModeledCacheListener<T>}}. + +h2. Example + +Here is an example of using ModeledTreeCache. The other modeled caches are similar. + +{code} +// given a model class "Person" + +ModeledTreeCache<Person> cache = ModeledTreeCache.wrap(makeTreeCache(), serializer); +ModeledCacheListener<Person> listener = event -> { + switch ( event.getType() ) { + case ModeledCacheEventType.NODE_ADDED: + Person person = event.getNode().getModel(); + handleNewPerson(person); + break; + ... + } +}; +cache.getListenable().addListener(listener); +{code} http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/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 0506f8e..118a731 100644 --- a/curator-x-async/src/site/confluence/modeled.confluence +++ b/curator-x-async/src/site/confluence/modeled.confluence @@ -18,7 +18,7 @@ Modeled Curator maps a ZooKeeper path to a DSL that allows for strongly typed CR and any children of the path. Bound into the DSL are all the various Curator options such as whether to watch nodes, compress data, use guaranteed delete, etc. You create an instance of this DSL once at startup so that it can be used without client code having to remember which serializer to use, which ACLs to -set, etc. +set, etc h4. Serialization http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-async/src/site/site.xml ---------------------------------------------------------------------- diff --git a/curator-x-async/src/site/site.xml b/curator-x-async/src/site/site.xml index 964353c..ca6d763 100644 --- a/curator-x-async/src/site/site.xml +++ b/curator-x-async/src/site/site.xml @@ -25,7 +25,7 @@ <link rel="stylesheet" href="../css/site.css" /> <script type="text/javascript"> $(function(){ - $('a[title="Curator Async"]').parent().addClass("active"); + $('a[title="Curator Java 8/Async"]').parent().addClass("active"); }); </script> </head> http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/recipes/TestModeledCaches.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/recipes/TestModeledCaches.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/recipes/TestModeledCaches.java index ce65f9c..5f748fd 100644 --- a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/recipes/TestModeledCaches.java +++ b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/recipes/TestModeledCaches.java @@ -91,9 +91,8 @@ public class TestModeledCaches extends CompletableBaseClassForTests Assert.assertNotNull(event); Assert.assertEquals(event.getType(), ModeledCacheEventType.NODE_UPDATED); Assert.assertTrue(event.getNode().isPresent()); - Assert.assertTrue(event.getNode().get().getData().isPresent()); Assert.assertEquals(event.getNode().get().getPath(), path); - Assert.assertEquals(event.getNode().get().getData().get(), model1); + Assert.assertEquals(event.getNode().get().getModel(), model1); Assert.assertEquals(event.getNode().get().getStat(), stat); timing.sleepABit(); @@ -102,9 +101,8 @@ public class TestModeledCaches extends CompletableBaseClassForTests modeled.update(model2); event = events.poll(timing.milliseconds(), TimeUnit.MILLISECONDS); Assert.assertTrue(event.getNode().isPresent()); - Assert.assertTrue(event.getNode().get().getData().isPresent()); Assert.assertEquals(event.getNode().get().getPath(), path); - Assert.assertEquals(event.getNode().get().getData().get(), model2); + Assert.assertEquals(event.getNode().get().getModel(), model2); modeled.delete(); event = events.poll(timing.milliseconds(), TimeUnit.MILLISECONDS); @@ -113,7 +111,7 @@ public class TestModeledCaches extends CompletableBaseClassForTests } @Test - public void testModeledPathChildrenCacheWithData() throws InterruptedException + public void testModeledPathChildrenCache() throws InterruptedException { try ( ModeledPathChildrenCache<TestModel> cache = ModeledPathChildrenCache.wrap(new PathChildrenCache(client, path.fullPath(), true), serializer) ) { @@ -134,8 +132,8 @@ public class TestModeledCaches extends CompletableBaseClassForTests Assert.assertNotNull(event2); Assert.assertEquals(event1.getType(), ModeledCacheEventType.NODE_ADDED); Assert.assertEquals(event2.getType(), ModeledCacheEventType.NODE_ADDED); - Assert.assertEquals(event1.getNode().isPresent() ? event1.getNode().get().getData().orElse(null) : null, model1); - Assert.assertEquals(event2.getNode().isPresent() ? event2.getNode().get().getData().orElse(null) : null, model2); + Assert.assertEquals(event1.getNode().isPresent() ? event1.getNode().get().getModel() : null, model1); + Assert.assertEquals(event2.getNode().isPresent() ? event2.getNode().get().getModel() : null, model2); Assert.assertEquals(event1.getNode().get().getPath(), path.at("1")); Assert.assertEquals(event2.getNode().get().getPath(), path.at("2")); @@ -150,7 +148,7 @@ public class TestModeledCaches extends CompletableBaseClassForTests Assert.assertNotNull(event1); Assert.assertEquals(event1.getType(), ModeledCacheEventType.NODE_UPDATED); Assert.assertEquals(event1.getNode().get().getPath(), path.at("2")); - Assert.assertEquals(event1.getNode().isPresent() ? event1.getNode().get().getData().orElse(null) : null, model3); + Assert.assertEquals(event1.getNode().isPresent() ? event1.getNode().get().getModel() : null, model3); cache.getListenable().removeListener(listener); modeled.at("2").delete(); @@ -159,36 +157,9 @@ public class TestModeledCaches extends CompletableBaseClassForTests } @Test - public void testModeledPathChildrenCacheWithoutData() throws InterruptedException + public void testModeledTreeCache() throws Exception { - try ( ModeledPathChildrenCache<TestModel> cache = ModeledPathChildrenCache.wrap(new PathChildrenCache(client, path.fullPath(), false), serializer) ) - { - cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); - - BlockingQueue<ModeledCacheEvent<TestModel>> events = new LinkedBlockingQueue<>(); - ModeledCacheListener<TestModel> listener = events::add; - cache.getListenable().addListener(listener); - - TestModel model1 = new TestModel("a", "b", "c", 1, BigInteger.TEN); - TestModel model2 = new TestModel("d", "e", "f", 10, BigInteger.ONE); - - modeled.at("1").create(model1).thenApply(__ -> modeled.at("2").create(model2)); - ModeledCacheEvent<TestModel> event1 = events.poll(timing.milliseconds(), TimeUnit.MILLISECONDS); - ModeledCacheEvent<TestModel> event2 = events.poll(timing.milliseconds(), TimeUnit.MILLISECONDS); - Assert.assertNotNull(event1); - Assert.assertNotNull(event2); - Assert.assertEquals(event1.getType(), ModeledCacheEventType.NODE_ADDED); - Assert.assertTrue(event1.getNode().isPresent()); - Assert.assertTrue(event2.getNode().isPresent()); - Assert.assertFalse(event1.getNode().get().getData().isPresent()); - Assert.assertFalse(event2.getNode().get().getData().isPresent()); - } - } - - @Test - public void testModeledTreeCacheWithData() throws Exception - { - try (ModeledTreeCache<TestModel> cache = ModeledTreeCache.wrap(TreeCache.newBuilder(client, path.fullPath()).build(),serializer) ) + try (ModeledTreeCache<TestModel> cache = ModeledTreeCache.wrap(TreeCache.newBuilder(client, path.fullPath()).build(), serializer) ) { BlockingQueue<ModeledCacheEvent<TestModel>> events = new LinkedBlockingQueue<>(); ModeledCacheListener<TestModel> listener = ModeledCacheListener.filtered(events::add, ModeledCacheListener.<TestModel>nodeRemovedFilter().or(ModeledCacheListener.hasModelFilter())); @@ -210,9 +181,9 @@ public class TestModeledCaches extends CompletableBaseClassForTests Assert.assertEquals(event1.getType(), ModeledCacheEventType.NODE_ADDED); Assert.assertEquals(event2.getType(), ModeledCacheEventType.NODE_ADDED); Assert.assertEquals(event3.getType(), ModeledCacheEventType.NODE_ADDED); - Assert.assertEquals(event1.getNode().isPresent() ? event1.getNode().get().getData().orElse(null) : null, model1); - Assert.assertEquals(event2.getNode().isPresent() ? event2.getNode().get().getData().orElse(null) : null, model2); - Assert.assertEquals(event3.getNode().isPresent() ? event3.getNode().get().getData().orElse(null) : null, model3); + Assert.assertEquals(event1.getNode().isPresent() ? event1.getNode().get().getModel() : null, model1); + Assert.assertEquals(event2.getNode().isPresent() ? event2.getNode().get().getModel() : null, model2); + Assert.assertEquals(event3.getNode().isPresent() ? event3.getNode().get().getModel() : null, model3); Assert.assertEquals(event1.getNode().get().getPath(), path.at("1")); Assert.assertEquals(event2.getNode().get().getPath(), path.at("1").at("2")); Assert.assertEquals(event3.getNode().get().getPath(), path.at("1").at("2").at("3")); http://git-wip-us.apache.org/repos/asf/curator/blob/bf43232b/curator-x-rpc/src/site/site.xml ---------------------------------------------------------------------- diff --git a/curator-x-rpc/src/site/site.xml b/curator-x-rpc/src/site/site.xml index 135c902..fca1e73 100644 --- a/curator-x-rpc/src/site/site.xml +++ b/curator-x-rpc/src/site/site.xml @@ -25,7 +25,7 @@ <link rel="stylesheet" href="../css/site.css" /> <script type="text/javascript"> $(function(){ - $('a[title="Curator Async"]').parent().addClass("active"); + $('a[title="Curator RPC Proxy"]').parent().addClass("active"); }); </script> </head>