Repository: curator Updated Branches: refs/heads/CURATOR-397 8237fde0a -> 1dab81b5a
adding docs Project: http://git-wip-us.apache.org/repos/asf/curator/repo Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/1dab81b5 Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/1dab81b5 Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/1dab81b5 Branch: refs/heads/CURATOR-397 Commit: 1dab81b5afedc4a0669312b386936baf7715c080 Parents: 8237fde Author: randgalt <randg...@apache.org> Authored: Sat Apr 8 15:03:49 2017 -0500 Committer: randgalt <randg...@apache.org> Committed: Sat Apr 8 15:03:49 2017 -0500 ---------------------------------------------------------------------- .../x/async/modeled/JacksonModelSerializer.java | 6 + .../x/async/modeled/ModelSerializer.java | 16 ++ .../modeled/ModeledAsyncCuratorFramework.java | 19 ++ .../apache/curator/x/async/modeled/ZPath.java | 55 +++++ .../src/site/confluence/async.confluence | 212 +++++++++++++++++++ .../src/site/confluence/index.confluence | 210 ++---------------- .../src/site/confluence/modeled.confluence | 103 +++++++++ curator-x-async/src/site/site.xml | 2 +- src/site/site.xml | 3 +- 9 files changed, 430 insertions(+), 196 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/JacksonModelSerializer.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/JacksonModelSerializer.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/JacksonModelSerializer.java index 5fb6e07..90b120a 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/JacksonModelSerializer.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/JacksonModelSerializer.java @@ -28,6 +28,12 @@ import com.fasterxml.jackson.databind.ObjectWriter; import java.io.IOException; import java.util.Arrays; +/** + * Model serializer that uses Jackson for JSON serialization. <strong>IMPORTANT: </strong> + * the jackson dependency is specified as <code>provided</code> in the curator-x-async Maven POM + * file to avoid adding a new dependency to Curator. Therefore, if you wish to use the + * JacksonModelSerializer you must manually add the dependency to your build system. + */ public class JacksonModelSerializer<T> implements ModelSerializer<T> { private static final ObjectMapper mapper = new ObjectMapper(); http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSerializer.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSerializer.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSerializer.java index 64defdf..9828c26 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSerializer.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModelSerializer.java @@ -18,9 +18,25 @@ */ package org.apache.curator.x.async.modeled; +/** + * Serializing interface for models + */ public interface ModelSerializer<T> { + /** + * Given a model return the serialized bytes + * + * @param model model + * @return bytes + */ byte[] serialize(T model); + /** + * Given bytes serialized via {@link #serialize(Object)} return + * the model + * + * @param bytes serialized bytes + * @return model + */ T deserialize(byte[] bytes); } http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledAsyncCuratorFramework.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledAsyncCuratorFramework.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledAsyncCuratorFramework.java index fdcc259..6acc77c 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledAsyncCuratorFramework.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ModeledAsyncCuratorFramework.java @@ -30,11 +30,30 @@ public interface ModeledAsyncCuratorFramework<T> ImmutableSet<CreateOption> defaultCreateOptions = ImmutableSet.of(CreateOption.createParentsAsContainers, CreateOption.setDataIfExists); ImmutableSet<DeleteOption> defaultDeleteOptions = ImmutableSet.of(DeleteOption.guaranteed); + /** + * Return a new ModeledAsyncCuratorFramework for the given path and serializer. The returned ModeledAsyncCuratorFramework + * is set to not watch ZNodes and uses {@link #defaultCreateOptions} and {@link #defaultDeleteOptions}. + * + * @param client Curator client + * @param path path to model + * @param serializer the model's serializer + * @return Modeled Curator instance + */ static <T> ModeledAsyncCuratorFramework<T> wrap(CuratorFramework client, ZPath path, ModelSerializer<T> serializer) { return builder(client, path, serializer).build(); } + /** + * Start a new ModeledAsyncCuratorFrameworkBuilder for the given path and serializer. The returned ModeledAsyncCuratorFrameworkBuilder + * is set to not watch ZNodes and uses {@link #defaultCreateOptions} and {@link #defaultDeleteOptions}, but you can change these + * with builder methods. + * + * @param client Curator client + * @param path path to model + * @param serializer the model's serializer + * @return builder + */ static <T> ModeledAsyncCuratorFrameworkBuilder<T> builder(CuratorFramework client, ZPath path, ModelSerializer<T> serializer) { return new ModeledAsyncCuratorFrameworkBuilder<>(client, path, serializer) http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java index 7e24341..05d012a 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java @@ -2,15 +2,36 @@ package org.apache.curator.x.async.modeled; import org.apache.curator.x.async.modeled.details.ZPathImpl; +/** + * Abstracts a ZooKeeper ZNode path + */ public interface ZPath { + /** + * The root path: "/" + */ ZPath root = ZPathImpl.root; + /** + * Take a ZNode string path and return a ZPath + * + * @param fullPath the path to parse + * @return ZPath + * @throws IllegalArgumentException if the path is invalid + */ static ZPath parse(String fullPath) { return ZPathImpl.parse(fullPath); } + /** + * Convert individual path names into a ZPath. E.g. + * <code>ZPath.from("my", "full", "path")</code> + * + * @param names path names + * @return ZPath + * @throws IllegalArgumentException if any of the names is invalid + */ static ZPath from(String... names) { ZPath path = root; @@ -21,15 +42,49 @@ public interface ZPath return path; } + /** + * Return a ZPath that represents a child ZNode of this ZPath. e.g. + * <code>ZPath.from("a", "b").at("c")</code> represents the path "/a/b/c" + * + * @param child child node name + * @return ZPath + */ ZPath at(String child); + /** + * Return this ZPath's parent + * + * @return parent ZPath + * @throws java.util.NoSuchElementException if this is the root ZPath + */ ZPath parent(); + /** + * Return true/false if this is the root ZPath + * + * @return true false + */ boolean isRoot(); + /** + * The string full path that this ZPath represents + * + * @return full path + */ String fullPath(); + /** + * The string parent path of this ZPath + * + * @return parent path + * @throws java.util.NoSuchElementException if this is the root ZPath + */ String parentPath(); + /** + * The node name at this ZPath + * + * @return name + */ String nodeName(); } http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/curator-x-async/src/site/confluence/async.confluence ---------------------------------------------------------------------- diff --git a/curator-x-async/src/site/confluence/async.confluence b/curator-x-async/src/site/confluence/async.confluence new file mode 100644 index 0000000..619f5c8 --- /dev/null +++ b/curator-x-async/src/site/confluence/async.confluence @@ -0,0 +1,212 @@ +h1. Curator Async + +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]. For example: + +{code} +// let "client" be a CuratorFramework instance +AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client); +async.checkExists().forPath(somePath).thenAccept(stat -> mySuccessOperation(stat)); +{code} + +h2. Usage + +Note: To use Curator Async, you should be familiar with Java 8's lambdas, CompletedFuture and CompletionStage. + +Create a [[CuratorFramework|../curator\-framework/index.html]] instance in the normal way. You then wrap this instance using +AsyncCuratorFramework. i.e. + +{code} +// let "client" be a CuratorFramework instance +AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client); +{code} + +AsyncCuratorFramework has most of the same builder methods that CuratorFramework does with some important +differences: + +* AsyncCuratorFramework builders return {{AsyncStage}} instances +* AsyncCuratorFramework builders have no checked exceptions +* Many of the builder methods have been simplified/clarified +* All builders invoke the asynchronous versions of ZooKeeper APIs +* Watchers also use CompletionStages \- see below for details + +h4. AsyncStage + +AsyncStage instances extend Java 8's CompletionStage. CompletionStage objects can be "completed" with a success +value or an exception. The parameterized type of the AsyncStage will +be whatever the builder used would naturally return as a success value. E.g. the async getData() builder's AsyncStage is +parameterized with "byte\[\]". + +h4. Watchers + +ZooKeeper watchers also get the CompletionStage treatment in Curator Async. To add a watcher, call +watched() prior to starting the appropriate builders. E.g. + +{code} +async.watched().getData().forPath(path) ... +{code} + +Thus, a data watcher will be set on the specified path. You access the CompletionStage for the watcher +by using the event() method of AsyncStage. Here is a complete example: + +{code} +async.watched().getData().forPath(path).event().thenAccept(watchedEvent -> watchWasTriggered(watchedEvent)); +{code} + +ZooKeeper calls watchers when there is a connection loss. This can make using the CompletionStage +somewhat complicated (see AsyncEventException below). If you are not interested in watcher connection +problems, you can tell Curator Async to not send them by calling: + +{code} +// only complete the CompletionStage when the watcher is successfully triggered +// i.e. don't complete on connection issues +async.with(WatchMode.successOnly).watched()... +{code} + +h4. AsyncEventException + +When an async watcher fails the exception set in the CompletionStage will be of type {{AsyncEventException}}. +This exception allows you to see the KeeperState that caused the trigger and allows you to reset the +completion stage. Reset is needed because ZooKeeper temporarily triggers watchers when there is a connection +event (unless {{WatchMode.successOnly}} is used). However, the watcher stays set for the original operation. Use {{AsyncEventException#reset}} +to start a new completion stage that will wait on the next trigger of the watcher. + +E.g. + +{code} +AsyncStage stage = ... +stage.event().exceptionally(e -> { + AsyncEventException asyncEx = (AsyncEventException)e; + + ... note a connection problem ... + + asyncEx.reset().thenAccept(watchedEvent -> watchWasTriggered(watchedEvent)); +}); +{code} + +h4. AsyncResult + +As a convenience, you can use {{AsyncResult}} to combine ZooKeeper method value, the ZooKeeper result +code and any exception in one object allowing you to not worry about exceptional completions. i.e. the {{CompletionStage}} +returned by {{AsyncResult.of()}} always completes successfully with an AsyncResult object. + +AsyncResult has methods to get either the method result (a path, Stat, etc.), a KeeperException code +or a general exception: + +{code} +Optional<T> getValue(); + +KeeperException.Code getCode(); + +Optional<Throwable> getException(); +{code} + +Use AsyncResult by wrapping an {{AsyncStage}} value. i.e. + +{code} +CompletionStage<AsyncResult<Stat>> resultStage = AsyncResult.of(async.checkExists().forPath(path)); +resultStage.thenAccept(result -> { + if ( result.getValue().isPresent() ) { + // ... + } else if ( result.getCode() == KeeperException.Code.NOAUTH ) { + // ... + } + // etc. +}); +{code} + +h2. Examples + +h4. Create a sequential ZNode + +Create a sequential ZNode and, once successfully completed, set a watcher +on the ZNode. Note: this code does not deal with errors. Should a connection +problem occur or another exception occur, the completion lambda will never be called. + +{code} +async.create().withMode(PERSISTENT_SEQUENTIAL).forPath(path).thenAccept(actualPath -> + async.watched().getData().forPath(actualPath).thenApply(() -> watchTriggered())); +{code} + +---- + +h4. AsyncStage canonical usage + +This is the canonical way to deal with AsyncStage. Use the handle() method which provides +both the success value and the exception. The exception will be non\-null on error. + +{code} +async.create().withOptions(EnumSet.of(doProtected)).forPath(path).handle((actualPath, exception) -> { + if ( exception != null ) + { + // handle problem + } + else + { + // actualPath is the path created + } + return null; +}); +{code} + +---- + +h4. Simplified usage via AsyncResult + +{code} +AsyncResult.of(async.create().withOptions(EnumSet.of(doProtected)).forPath(path)).thenAccept(result -> { + if ( result.getRawValue() != null ) + { + // result.getRawValue() is the path created + } + else + { + // ... + } +}); +{code} + +---- + +h4. Using executors + +Your completion routines can operate in a separate thread if you provide an executor. + +{code} +async.create().withOptions(EnumSet.of(createParentsIfNeeded)).forPath("/a/b/c") + .thenAcceptAsync(path -> handleCreate(path), executor); +{code} + +---- + +h4. Separate handlers + +This example shows specifying separate completion handlers for success and exception. + +{code} +AsyncStage<byte[]> stage = async.getData().forPath("/my/path"); +stage.exceptionally(e -> { + if ( e instanceof KeeperException.NoNodeException ) + { + // handle no node + } + else + { + // handle other + } + return null; +}); +stage.thenAccept(data -> processData(data)); +{code} + +---- + +h4. Synchronous usage + +CompletionStage provides a blocking method as well so that you can block to get the result +of an operation. i.e. this makes it possible to use the async APIs in a synchronous way. + +{code} +// NOTE: get() specifies a checked exception +async.create().forPath("/foo").toCompletableFuture().get(); +{code} http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/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 34b6c36..3ea8b4c 100644 --- a/curator-x-async/src/site/confluence/index.confluence +++ b/curator-x-async/src/site/confluence/index.confluence @@ -4,7 +4,7 @@ h2. Packaging Curator Async is in its own package in Maven Central: curator\-x\-async -h2. What Is a Curator Async? +h2. What Is Curator Async? Curator Async is a [DSL|https://en.wikipedia.org/wiki/Domain-specific_language] that wraps existing {{CuratorFramework}} instances. This DSL is entirely asynchronous and uses @@ -13,212 +13,34 @@ mechanism for chaining, composing, etc. Additionally, Curator's original DSL has 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]. For example: - -{code} -// let "client" be a CuratorFramework instance -AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client); -async.checkExists().forPath(somePath).thenAccept(stat -> mySuccessOperation(stat)); -{code} +[Java 8 lambdas|https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html]. -h2. Usage +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. -Note: To use Curator Async, you should be familiar with Java 8's lambdas, CompletedFuture and CompletionStage. +h2. [[Curator Async|async.html]] -Create a [[CuratorFramework|../curator\-framework/index.html]] instance in the normal way. You then wrap this instance using -AsyncCuratorFramework. i.e. +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]. For example: {code} // let "client" be a CuratorFramework instance AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client); +async.checkExists().forPath(somePath).thenAccept(stat -> mySuccessOperation(stat)); {code} -AsyncCuratorFramework has most of the same builder methods that CuratorFramework does with some important -differences: - -* AsyncCuratorFramework builders return {{AsyncStage}} instances -* AsyncCuratorFramework builders have no checked exceptions -* Many of the builder methods have been simplified/clarified -* All builders invoke the asynchronous versions of ZooKeeper APIs -* Watchers also use CompletionStages \- see below for details - -h4. AsyncStage - -AsyncStage instances extend Java 8's CompletionStage. CompletionStage objects can be "completed" with a success -value or an exception. The parameterized type of the AsyncStage will -be whatever the builder used would naturally return as a success value. E.g. the async getData() builder's AsyncStage is -parameterized with "byte\[\]". - -h4. Watchers - -ZooKeeper watchers also get the CompletionStage treatment in Curator Async. To add a watcher, call -watched() prior to starting the appropriate builders. E.g. - -{code} -async.watched().getData().forPath(path) ... -{code} - -Thus, a data watcher will be set on the specified path. You access the CompletionStage for the watcher -by using the event() method of AsyncStage. Here is a complete example: - -{code} -async.watched().getData().forPath(path).event().thenAccept(watchedEvent -> watchWasTriggered(watchedEvent)); -{code} - -ZooKeeper calls watchers when there is a connection loss. This can make using the CompletionStage -somewhat complicated (see AsyncEventException below). If you are not interested in watcher connection -problems, you can tell Curator Async to not send them by calling: - -{code} -// only complete the CompletionStage when the watcher is successfully triggered -// i.e. don't complete on connection issues -async.with(WatchMode.successOnly).watched()... -{code} - -h4. AsyncEventException - -When an async watcher fails the exception set in the CompletionStage will be of type {{AsyncEventException}}. -This exception allows you to see the KeeperState that caused the trigger and allows you to reset the -completion stage. Reset is needed because ZooKeeper temporarily triggers watchers when there is a connection -event (unless {{WatchMode.successOnly}} is used). However, the watcher stays set for the original operation. Use {{AsyncEventException#reset}} -to start a new completion stage that will wait on the next trigger of the watcher. - -E.g. - -{code} -AsyncStage stage = ... -stage.event().exceptionally(e -> { - AsyncEventException asyncEx = (AsyncEventException)e; - - ... note a connection problem ... - - asyncEx.reset().thenAccept(watchedEvent -> watchWasTriggered(watchedEvent)); -}); -{code} - -h4. AsyncResult - -As a convenience, you can use {{AsyncResult}} to combine ZooKeeper method value, the ZooKeeper result -code and any exception in one object allowing you to not worry about exceptional completions. i.e. the {{CompletionStage}} -returned by {{AsyncResult.of()}} always completes successfully with an AsyncResult object. - -AsyncResult has methods to get either the method result (a path, Stat, etc.), a KeeperException code -or a general exception: - -{code} -Optional<T> getValue(); - -KeeperException.Code getCode(); - -Optional<Throwable> getException(); -{code} - -Use AsyncResult by wrapping an {{AsyncStage}} value. i.e. - -{code} -CompletionStage<AsyncResult<Stat>> resultStage = AsyncResult.of(async.checkExists().forPath(path)); -resultStage.thenAccept(result -> { - if ( result.getValue().isPresent() ) { - // ... - } else if ( result.getCode() == KeeperException.Code.NOAUTH ) { - // ... - } - // etc. -}); -{code} - -h2. Examples - -h4. Create a sequential ZNode - -Create a sequential ZNode and, once successfully completed, set a watcher -on the ZNode. Note: this code does not deal with errors. Should a connection -problem occur or another exception occur, the completion lambda will never be called. - -{code} -async.create().withMode(PERSISTENT_SEQUENTIAL).forPath(path).thenAccept(actualPath -> - async.watched().getData().forPath(actualPath).thenApply(() -> watchTriggered())); -{code} - ----- - -h4. AsyncStage canonical usage - -This is the canonical way to deal with AsyncStage. Use the handle() method which provides -both the success value and the exception. The exception will be non\-null on error. - -{code} -async.create().withOptions(EnumSet.of(doProtected)).forPath(path).handle((actualPath, exception) -> { - if ( exception != null ) - { - // handle problem - } - else - { - // actualPath is the path created - } - return null; -}); -{code} - ----- - -h4. Simplified usage via AsyncResult - -{code} -AsyncResult.of(async.create().withOptions(EnumSet.of(doProtected)).forPath(path)).thenAccept(result -> { - if ( result.getRawValue() != null ) - { - // result.getRawValue() is the path created - } - else - { - // ... - } -}); -{code} - ----- - -h4. Using executors - -Your completion routines can operate in a separate thread if you provide an executor. - -{code} -async.create().withOptions(EnumSet.of(createParentsIfNeeded)).forPath("/a/b/c") - .thenAcceptAsync(path -> handleCreate(path), executor); -{code} - ----- +See [[Curator Async|async.html]] for details. -h4. Separate handlers +h2. [[Modeled Curator|modeled.html]] -This example shows specifying separate completion handlers for success and exception. +This is a strongly typed DSL that allows you to map a ZooKeeper path to a serializable class as +opposed to raw byte arrays. For example: {code} -AsyncStage<byte[]> stage = async.getData().forPath("/my/path"); -stage.exceptionally(e -> { - if ( e instanceof KeeperException.NoNodeException ) - { - // handle no node - } - else - { - // handle other - } - return null; -}); -stage.thenAccept(data -> processData(data)); +// let "client" be a CuratorFramework instance +ModeledAsyncCuratorFramework<MyModel> modeled = ModeledAsyncCuratorFramework.wrap(client, path, serializer); +modeled.create(new MyModel()); {code} ----- +See [[Modeled Curator|modeled.html]] for details. -h4. Synchronous usage - -CompletionStage provides a blocking method as well so that you can block to get the result -of an operation. i.e. this makes it possible to use the async APIs in a synchronous way. - -{code} -// NOTE: get() specifies a checked exception -async.create().forPath("/foo").toCompletableFuture().get(); -{code} http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/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 new file mode 100644 index 0000000..0506f8e --- /dev/null +++ b/curator-x-async/src/site/confluence/modeled.confluence @@ -0,0 +1,103 @@ +h1. Modeled Curator + +This is a strongly typed DSL that allows you to map a ZooKeeper path to a serializable class as +opposed to raw byte arrays. For example: + +{code} +// let "client" be a CuratorFramework instance +ModeledAsyncCuratorFramework<MyModel> modeled = ModeledAsyncCuratorFramework.wrap(client, path, serializer); +modeled.create(new MyModel()); +{code} + +h2. Background and Usage + +Note: To use Modeled Curator, you should be familiar with Java 8's lambdas, CompletedFuture and CompletionStage. +You should also be familiar with [[Curator Async|async.html]] as Modeled Curator is based on it. + +Modeled Curator maps a ZooKeeper path to a DSL that allows for strongly typed CRUD operations on that path +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. + +h4. Serialization + +{{ModelSerializer}} is the interface for serializing/deserializing model instances. For convenience +a [[Jackson|https://github.com/FasterXML/jackson]] serializer is provided, {{JacksonModelSerializer}}. +However, please note that the dependency on Jackson is marked as {{provided}} so as not to introduce +a new dependency for using Curator. Therefore, if you wish to use the JacksonModelSerializer you must +manually add the dependency to your build system. + +h4. Path Abstraction + +Instead of using raw string paths, Modeled Curator defines the {{ZPath}} interface that abstracts +ZooKeeper paths. + +h4. Building + +You build a {{ModeledAsyncCuratorFramework}} 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 +* the ZNode {{CreateMode}} +* any {{CreateOption}}s +* any {{DeleteOption}}s +* any ACLs +* etc. + +These options are bound into the {{ModeledAsyncCuratorFramework}} instance and applied as needed. + +h2. Example + +For this example, assume this simple model: + +{code} +public class Person { + private final String name; + private final int age; + + public Person() { + this("", 0); + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } +} +{code} + +We can now build a {{ModeledAsyncCuratorFramework}} that manages {{Person}} instances at a given path: + +{code} +// let "client" be a CuratorFramework instance + +ZPath path = ZPath.parse(...); // whatever path you need +JacksonModelSerializer<Person> serializer = JacksonModelSerializer.build(Person.class); +ModeledAsyncCuratorFramework<MyModel> modeled = ModeledAsyncCuratorFramework.wrap(client, path, serializer); + +... + +public void writePerson(String id, Person p) { + modeled.at(id).create(p); // note this is an async operation +} + +public void readPerson(String id, Consumer<Person> receiver) { + modeled.at(id).read().whenComplete((person, exception) -> { + if ( exception != null ) { + ... + } else { + receiver.accept(person); + } + }); +} + +{code} http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/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 63fccaa..964353c 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 RPC Proxy"]').parent().addClass("active"); + $('a[title="Curator Async"]').parent().addClass("active"); }); </script> </head> http://git-wip-us.apache.org/repos/asf/curator/blob/1dab81b5/src/site/site.xml ---------------------------------------------------------------------- diff --git a/src/site/site.xml b/src/site/site.xml index 222ffde..9f87bd6 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -73,6 +73,7 @@ <item name="Framework" href="curator-framework/index.html"/> <item name="Utilities" href="utilities.html"/> <item name="Client" href="curator-client/index.html"/> + <item name="Java 8/Async" href="curator-x-async/index.html"/> <item name="Schema Support" href="curator-framework/schema.html"/> </menu> @@ -94,7 +95,7 @@ <item name="Service Discovery" href="curator-x-discovery/index.html"/> <item name="Service Discovery Server" href="curator-x-discovery-server/index.html"/> <item name="Curator RPC Proxy" href="curator-x-rpc/index.html"/> - <item name="Curator Async" href="curator-x-async/index.html"/> + <item name="Curator Java 8/Async" href="curator-x-async/index.html"/> </menu> <menu name="Community" inherit="top">