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 2014/06/01 20:15:46 UTC

[1/3] git commit: wip on doc

Repository: curator
Updated Branches:
  refs/heads/curator-rpc bf4ceb429 -> bfc388ce0


wip on doc


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

Branch: refs/heads/curator-rpc
Commit: 78460f9041ceb10d641a059773c6b68cab611144
Parents: bf4ceb4
Author: randgalt <ra...@apache.org>
Authored: Sun Jun 1 11:53:56 2014 -0500
Committer: randgalt <ra...@apache.org>
Committed: Sun Jun 1 11:53:56 2014 -0500

----------------------------------------------------------------------
 .../src/main/resources/curator/help.txt         |   1 +
 curator-x-rpc/src/main/scripts/apply-thrift.sh  |  39 +++++
 curator-x-rpc/src/main/scripts/generate-java.sh |  28 ----
 curator-x-rpc/src/main/scripts/generate.sh      |   2 +-
 .../site/confluence/configuration.confluence    | 150 +++++++++++++++++
 .../src/site/confluence/deploy.confluence       |  10 +-
 .../src/site/confluence/index.confluence        |  31 ++--
 .../src/site/confluence/usage.confluence        |  27 +++
 .../org/apache/curator/x/rpc/TestClient.java    | 167 -------------------
 .../org/apache/curator/x/rpc/TestServer.java    |  34 ----
 .../configuration/TestConfigurationBuilder.java |  83 ---------
 11 files changed, 243 insertions(+), 329 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/main/resources/curator/help.txt
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/resources/curator/help.txt b/curator-x-rpc/src/main/resources/curator/help.txt
index 53e751f..7479e23 100644
--- a/curator-x-rpc/src/main/resources/curator/help.txt
+++ b/curator-x-rpc/src/main/resources/curator/help.txt
@@ -29,6 +29,7 @@ the model configuration shown in JSON with added comments. Required fields have
 
     "connections": [ // * list of ZooKeeper connections
         "name": "string", // * unique name for the connection
+        "connectionString": "string", // * ZooKeeper connection string (e.g. "host1:2181,host2:2181")
         "sessionLength": "Duration", // duration for the session. Default is 1 minute.
         "connectionTimeout": "Duration", // duration for connecting. Default is 15 seconds.
         "authorization": { // Authorization spec. Default is NULL.

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/main/scripts/apply-thrift.sh
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/scripts/apply-thrift.sh b/curator-x-rpc/src/main/scripts/apply-thrift.sh
new file mode 100755
index 0000000..e2a0d85
--- /dev/null
+++ b/curator-x-rpc/src/main/scripts/apply-thrift.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# 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.
+#
+
+
+if (( $# == 0 )); then
+    echo -e "usage:\n\tapply-thrift.sh <language code> <optional target directory>"
+    exit
+fi
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+BASE_DIR="$( cd "$DIR/../../../.." && pwd )"
+
+if (( $# == 2 )); then
+    TARGET_DIR="$2"
+else
+    TARGET_DIR="$BASE_DIR/curator-x-rpc/src/test/java"
+fi
+
+mkdir -p "$TARGET_DIR/"
+rm -fr "$TARGET_DIR/"*
+
+thrift -gen $1 -out "$TARGET_DIR" "$BASE_DIR/curator-x-rpc/src/main/thrift/curator.thrift"

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/main/scripts/generate-java.sh
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/scripts/generate-java.sh b/curator-x-rpc/src/main/scripts/generate-java.sh
deleted file mode 100755
index b667fb1..0000000
--- a/curator-x-rpc/src/main/scripts/generate-java.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-#
-# 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.
-#
-
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-BASE_DIR="$( cd "$DIR/../../../.." && pwd )"
-TARGET_DIR="$BASE_DIR/curator-x-rpc/src/test/java"
-
-rm "$TARGET_DIR/org/apache/curator/generated/"*
-
-thrift -gen java -out "$TARGET_DIR" "$BASE_DIR/curator-x-rpc/src/main/thrift/curator.thrift"

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/main/scripts/generate.sh
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/scripts/generate.sh b/curator-x-rpc/src/main/scripts/generate.sh
index 4c76ffa..ddcbff4 100755
--- a/curator-x-rpc/src/main/scripts/generate.sh
+++ b/curator-x-rpc/src/main/scripts/generate.sh
@@ -20,7 +20,7 @@
 
 
 if (( $# != 2 )); then
-    echo "usage:\ngenerate.sh <path to swift2thrift-generator-cli-N.N.N-standalone.jar> <path to zookeeper-N.N.N.jar>"
+    echo -e "usage:\n\tgenerate.sh <path to swift2thrift-generator-cli-N.N.N-standalone.jar> <path to zookeeper-N.N.N.jar>"
     exit
 fi
 

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/site/confluence/configuration.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/configuration.confluence b/curator-x-rpc/src/site/confluence/configuration.confluence
new file mode 100644
index 0000000..d2ae8c8
--- /dev/null
+++ b/curator-x-rpc/src/site/confluence/configuration.confluence
@@ -0,0 +1,150 @@
+[[Curator RPC Proxy|index.html]] / Configuration
+
+h1. Configuration
+
+h2. Introduction
+
+Curator RPC uses [[Dropwizard|http://dropwizard.readthedocs.org/en/latest/]] for configuration. You can write the configuration in JSON or YAML.
+It can be passed to Curator RPC via a file or directly on the command line. i.e.
+
+{noformat}
+# via command line
+java -jar curator-x-rpc-VERSION.jar '{"thrift":{"port": 8080}}'
+{noformat}
+
+{noformat}
+# via file
+java -jar curator-x-rpc-VERSION.jar path/to/config.json
+{noformat}
+
+h2. Example
+
+Here is an example JSON configuration file
+
+{noformat}
+{
+    "projectionExpiration": "15s",
+
+    "thrift": {
+        "port": 1234
+    },
+
+    "pingTime": "10s",
+
+    "logging": {
+        "level": "INFO",
+
+        "appenders": [
+            {
+                "type": "file",
+                "currentLogFilename": "logs/curator-rpc.log",
+                "archivedLogFilenamePattern": "logs/curator-rpc-%d.log.gz",
+                "archivedFileCount": 10,
+                "timeZone": "UTC"
+            },
+
+            {
+                "type": "console"
+            }
+        ]
+    },
+
+    "connections": [
+        {
+            "name": "main",
+            "connectionString": "one:1,two:2",
+            "sessionLength": "3m",
+            "connectionTimeout": "20s",
+            "retry": {
+                "type": "exponential-backoff",
+                "baseSleepTime": "1s",
+                "maxRetries": 10
+            }
+        },
+
+        {
+            "name": "alt",
+            "connectionString": "three:3,four:4",
+            "sessionLength": "4m",
+            "connectionTimeout": "30s",
+            "retry": {
+                "type": "ntimes",
+                "sleepBetweenRetries": "1m",
+                "n": 10
+            }
+        }
+    ]
+}
+{noformat}
+
+
+h2. Reference
+
+h3. Main
+
+||Name||Type||Default Value||Description||
+|thrift|Thrift|n/a|Thrift server configuration|
+|logging|Logging|n/a|log file configuration|
+|projectionExpiration|Duration|3 minutes|Curator Projection instances will be automatically closed if not accessed within this amount of time|
+|pingTime|Duration|5 seconds|The EventService will return a PING event if this time elapses without some other event being generated|
+|connections|List of Connection|n/a|List of ZooKeeper connections|
+
+h3. Duration
+
+Durations are strings that specify a time duration. Examples:
+* "10s" \- 10 seconds
+* "100ms" \- 100 milliseconds
+* "3h" \- 3 hours
+
+h3. Thrift
+
+||Name||Type||Default Value||Description||
+|bindAddress|string|"bindAddress"|Address for server to bind to|
+|port|int|_none_|port to listen on. *required*|
+|idleConnectionTimeout|int|60 seconds|timeout period between receiving requests from a client connection. If the timeout is exceeded (no complete requests have arrived from the client within the timeout), the server will disconnect the idle client.|
+|transportName|string|"framed"|the name of the transport (frame codec) that this server will handle. The available options by default are 'unframed', 'buffered', and 'framed'. Additional modules may install other options.|
+|protocolName|string|"binary"|name of the protocol that this server will speak. The available options by default are 'binary' and 'compact'. Additional modules may install other options.|
+
+h3. Logging
+
+Dropwizard's logging module is used. See the [[Dropwizard Logging Doc|http://dropwizard.readthedocs.org/en/latest/manual/configuration.html#logging]] for details
+on specifying the logging configuration.
+
+h3. Connection
+
+||Name||Type||Default Value||Description||
+|name|string|_none_|Unique name for the connection. *required*|
+|connectionString|string|_none_|ZooKeeper connection string (e.g. "host1:2181,host2:2181"). *required*|
+|sessionLength|Duration|1 minute|duration for the ZooKeeper session|
+|connectionTimeout|Duration|15 seconds|duration for connecting|
+|retry|Retry|an exponential\-backoff policy|The Retry Policy to use|
+|authorization|Authorization|null|Authorization spec|
+
+h3. Retry
+
+The retry policy configuration depends on what type is used. There 3 types supported:
+
+_exponential\-backoff_
+||Name||Type||Default Value||Description||
+|type|string|n/a|"exponential\-backoff"|
+|baseSleepTime|Duration|100 milliseconds|The base sleep time|
+|maxRetries|int|3|The max retries|
+
+_bounded\-exponential\-backoff_
+||Name||Type||Default Value||Description||
+|type|string|n/a|"bounded\-exponential\-backoff"|
+|baseSleepTime|Duration|100 milliseconds|The base sleep time|
+|maxSleepTime|Duration|30 seconds|The max sleep time|
+|maxRetries|int|3|The max retries|
+
+_ntimes_
+||Name||Type||Default Value||Description||
+|type|string|n/a|"ntimes"|
+|sleepBetweenRetries|int|100 milliseconds|sleep time between retries|
+|n|int|3|the number of retries|
+
+h3. Authorization
+
+||Name||Type||Description||
+|scheme|string|the authorization scheme|
+|auth|string|the authorization auth|

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/site/confluence/deploy.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/deploy.confluence b/curator-x-rpc/src/site/confluence/deploy.confluence
index cb4612a..af3b682 100644
--- a/curator-x-rpc/src/site/confluence/deploy.confluence
+++ b/curator-x-rpc/src/site/confluence/deploy.confluence
@@ -2,13 +2,19 @@
 
 h1. Deployment
 
+h2. Running
+
 Curator RPC is built as an "uber" Java JAR and can be downloaded from Maven Central. Go to [[http://search.maven.org/]] and search for
 "curator\-x\-rpc" and download the JAR for the latest version. This JAR can be run directly ala:
 
 {noformat}
-java -jar curator-x-rpc-VERSION.jar
+java -jar curator-x-rpc-VERSION.jar <argument>
 {noformat}
 
+The argument is either a configuration file or a JSON or YAML string. See [[Configuration|configuration.html]] for details.
+
+h2. Deploying
+
 Curator RPC is designed to have an instance of its Thrift Server co\-located on each client instance that needs to connect to ZooKeeper
 (see the figure below). Each Curator RPC instance is configured (see [[Configuration|configuration.html]]) to connect to one or more
 ZooKeeper clusters. The Curator Framework instances are maintained inside of the Curator RPC instances and RPC clients reference these instances by ID.
@@ -20,4 +26,6 @@ How you configure your server to launch depends on your environment and other ne
 * [One-JAR|http://one-jar.sourceforge.net/]
 * [Capsule|https://github.com/puniverse/capsule]
 
+h2. Topology
+
 !images/topology.png!

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/site/confluence/index.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/index.confluence b/curator-x-rpc/src/site/confluence/index.confluence
index ece5769..f29aff9 100644
--- a/curator-x-rpc/src/site/confluence/index.confluence
+++ b/curator-x-rpc/src/site/confluence/index.confluence
@@ -2,30 +2,31 @@ h1. Curator RPC Proxy
 
 NOTE: Curator RPC Proxy is in its own package in Maven Central: curator\-x\-rpc
 
-The Curator RPC module implements a proxy that bridges non-java environments with the Curator framework and recipes. It uses
+The Curator RPC module implements a proxy that bridges non\-java environments with the Curator framework and recipes. It uses
 [[Apache Thrift|http://thrift.apache.org]] which supports a large set of languages and environments.
 
+The benefits of Curator RPC are:
+
+* Gives access to Curator to non JVM languages/environments
+** Curator has become the de\-facto JVM client library for ZooKeeper
+** Curator makes using Apache ZooKeeper much easier
+** Curator contains well\-tested recipes for many common ZooKeeper usages
+* Organizations can unify their ZooKeeper usage across languages/environments (i.e. use Curator's Service Discovery recipe)
+* The quality of ZooKeeper clients for some non\-JVM languages is lacking
+* There are Thrift implementations for a large number of languages/environments
+
 h2. Thrift File
 The current Curator RPC Thrift File can be found here: [[https://raw.githubusercontent.com/apache/curator/master/curator-x-rpc/src/main/thrift/curator.thrift]]. Use
 this to generate code for the language/environment you need.
 
-h2. Building and Packaging
-
-See the [[Building and Packaging Page|build.html]] for details on building and packaging the REST proxy.
-
 h2. Deployment
 
-See the [[Deployment Page|deploy.html]] for details on deploying the REST proxy.
-
-h2. Your REST Client
-
-See the [[REST Client|client.html]] for details on how to write a REST client that interacts with the proxy.
-
-h2. APIs
+See the [[Deployment Page|deploy.html]] for details on deploying the RPC proxy.
 
-See the [[APIs Page|apis.html]] for list of available APIs.
+h2. Usage
 
-h2. Entities
+See the [[Usage Page|usage.html]] for details on using the RPC proxy.
 
-See the [[Entity Descriptions Page|entities.html]] for details on the Entities used in the APIs.
+h2. Configuration
 
+See the [[Configuration|configuration.html]] for details on configuring the RPC proxy.

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/site/confluence/usage.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/usage.confluence b/curator-x-rpc/src/site/confluence/usage.confluence
new file mode 100644
index 0000000..a20c13f
--- /dev/null
+++ b/curator-x-rpc/src/site/confluence/usage.confluence
@@ -0,0 +1,27 @@
+[[Curator RPC Proxy|index.html]] / Usage
+
+h1. Usage
+
+h2. Thrift File
+
+The first step in using the RPC Proxy is to process the Curator RPC Thrift file into your desired language/environment.
+The current Curator RPC Thrift File can be found here: [[https://raw.githubusercontent.com/apache/curator/master/curator-x-rpc/src/main/thrift/curator.thrift]].
+Details on using Apache Thrift can be found here: [[http://thrift.apache.org]].
+
+h2. Prerequisites
+
+It's assumed you already familiar with ZooKeeper and Curator. Also, familiarity with writing Thrift applications is helpful.
+
+h2. Services
+
+Three Thrift Services are included with the Curator RPC:
+
+||Service||Description||
+|CuratorService|The main service for accessing the Curator APIs and recipes|
+|EventService|Used to receive out-of-band messages for callbacks, watchers, etc|
+|DiscoveryService|Curator's ServiceDiscovery recipe|
+
+h2. Concepts
+
+_Projections - Many of the Curator RPC APIs refer to "projections" (e.g. CuratorProjection). A projection is an id that refers
+to a real object instance inside of the RPC server.

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java
deleted file mode 100644
index 43a2ffc..0000000
--- a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java
+++ /dev/null
@@ -1,167 +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.rpc;
-
-import org.apache.curator.generated.*;
-import org.apache.thrift.TException;
-import org.apache.thrift.protocol.TBinaryProtocol;
-import org.apache.thrift.protocol.TProtocol;
-import org.apache.thrift.transport.TSocket;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.concurrent.Executors;
-
-public class TestClient
-{
-    public static void main(String[] args) throws Exception
-    {
-        TSocket clientTransport = new TSocket("localhost", 8899);
-        clientTransport.open();
-        TProtocol clientProtocol = new TBinaryProtocol(clientTransport);
-        final CuratorService.Client client = new CuratorService.Client(clientProtocol);
-
-        TSocket eventTransport = new TSocket("localhost", 8899);
-        eventTransport.open();
-        TProtocol eventProtocol = new TBinaryProtocol(eventTransport);
-        final EventService.Client serviceClient = new EventService.Client(eventProtocol);
-
-        TSocket discoveryTransport = new TSocket("localhost", 8899);
-        discoveryTransport.open();
-        TProtocol discoveryProtocol = new TBinaryProtocol(discoveryTransport);
-        final DiscoveryService.Client discoveryClient = new DiscoveryService.Client(discoveryProtocol);
-
-        final CuratorProjection curatorProjection = client.newCuratorProjection("test");
-
-        Executors.newSingleThreadExecutor().submit
-        (
-            new Runnable()
-            {
-                @Override
-                public void run()
-                {
-                    try
-                    {
-                        //noinspection InfiniteLoopStatement
-                        for(;;)
-                        {
-                            CuratorEvent nextEvent = serviceClient.getNextEvent(curatorProjection);
-                            System.out.println(nextEvent);
-                        }
-                    }
-                    catch ( TException e )
-                    {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        );
-
-        CreateSpec createSpec = new CreateSpec();
-        createSpec.path = "/this/should/fail";
-        createSpec.data = ByteBuffer.wrap("hey".getBytes());
-        try
-        {
-            client.createNode(curatorProjection, createSpec);
-        }
-        catch ( CuratorException e )
-        {
-            System.out.println("Ex: " + e);
-        }
-
-        createSpec = new CreateSpec();
-        createSpec.path = "/a/b/c";
-        createSpec.creatingParentsIfNeeded = true;
-        createSpec.data = ByteBuffer.wrap("hey".getBytes());
-        OptionalPath path = client.createNode(curatorProjection, createSpec);
-        System.out.println("Path: " + path);
-
-        PathChildrenCacheProjection pathChildrenCacheProjection = client.startPathChildrenCache(curatorProjection, "/a/b", true, false, PathChildrenCacheStartMode.BUILD_INITIAL_CACHE);
-
-        NodeCacheProjection nodeCache = client.startNodeCache(curatorProjection, "/a/b/c", false, true);
-        ChildData nodeCacheData = client.getNodeCacheData(curatorProjection, nodeCache);
-        System.out.println("nodeCacheData: " + nodeCacheData);
-
-        List<ChildData> pathChildrenCacheData = client.getPathChildrenCacheData(curatorProjection, pathChildrenCacheProjection);
-        System.out.println("Child data: " + pathChildrenCacheData);
-
-        GetChildrenSpec getChildrenSpec = new GetChildrenSpec();
-        getChildrenSpec.path = "/a";
-        OptionalChildrenList children = client.getChildren(curatorProjection, getChildrenSpec);
-        System.out.println("Children: " + children);
-
-        ChildData pathChildrenCacheDataForPath = client.getPathChildrenCacheDataForPath(curatorProjection, pathChildrenCacheProjection, "/a/b/c");
-        System.out.println(pathChildrenCacheDataForPath);
-
-        LockProjection lockId = client.acquireLock(curatorProjection, "/mylock", 1000);
-        client.closeGenericProjection(curatorProjection, lockId.id);
-
-        GetDataSpec getDataSpec = new GetDataSpec();
-        getDataSpec.watched = true;
-        getDataSpec.path = "/a/b/c";
-        ByteBuffer data = client.getData(curatorProjection, getDataSpec);
-        System.out.println("getData: " + new String(data.array()));
-
-        ExistsSpec existsSpec = new ExistsSpec();
-        existsSpec.path = "/a/b/c";
-        System.out.println("exists: " + client.exists(curatorProjection, existsSpec));
-
-        DeleteSpec deleteSpec = new DeleteSpec();
-        deleteSpec.path = "/a/b/c";
-        client.deleteNode(curatorProjection, deleteSpec);
-
-        System.out.println("exists: " + client.exists(curatorProjection, existsSpec));
-
-        LeaderResult leader = client.startLeaderSelector(curatorProjection, "/leader", "me", 10000);
-        System.out.println("Has Leader: " + leader.hasLeadership);
-
-        List<Participant> leaderParticipants = client.getLeaderParticipants(curatorProjection, leader.projection);
-        System.out.println("Participants: " + leaderParticipants);
-
-        boolean isLeader = client.isLeader(curatorProjection, leader.projection);
-        System.out.println("isLeader: " + isLeader);
-
-        client.closeGenericProjection(curatorProjection, leader.projection.id);
-
-        pathChildrenCacheData = client.getPathChildrenCacheData(curatorProjection, pathChildrenCacheProjection);
-        System.out.println("Child data: " + pathChildrenCacheData);
-
-        nodeCacheData = client.getNodeCacheData(curatorProjection, nodeCache);
-        System.out.println("nodeCacheData: " + nodeCacheData);
-
-        PersistentEphemeralNodeProjection node = client.startPersistentEphemeralNode(curatorProjection, "/my/path", ByteBuffer.wrap("hey".getBytes()), PersistentEphemeralNodeMode.EPHEMERAL);
-        existsSpec.path = "/my/path";
-        OptionalStat nodeExists = client.exists(curatorProjection, existsSpec);
-        System.out.println("nodeExists: " + nodeExists);
-        client.closeGenericProjection(curatorProjection, node.id);
-
-        List<LeaseProjection> leaseProjections = client.startSemaphore(curatorProjection, "/semi", 3, 1000, 10);
-        System.out.println("leaseProjections: " + leaseProjections);
-        for ( LeaseProjection leaseProjection : leaseProjections )
-        {
-            client.closeGenericProjection(curatorProjection, leaseProjection.id);
-        }
-
-        DiscoveryInstance yourInstance = discoveryClient.makeDiscoveryInstance("mine", ByteBuffer.wrap(new byte[]{}), 8080);
-        DiscoveryProjection discovery = discoveryClient.startDiscovery(curatorProjection, "/discovery", yourInstance);
-        DiscoveryProviderProjection provider = discoveryClient.startProvider(curatorProjection, discovery, "mine", ProviderStrategyType.ROUND_ROBIN, 1000, 3);
-
-        DiscoveryInstance instance = discoveryClient.getInstance(curatorProjection, provider);
-        System.out.println("Instance: " + instance);
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java
deleted file mode 100644
index 3564777..0000000
--- a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java
+++ /dev/null
@@ -1,34 +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.rpc;
-
-import com.google.common.io.Resources;
-import org.apache.curator.test.TestingServer;
-import java.nio.charset.Charset;
-
-public class TestServer
-{
-    public static void main(String[] args) throws Exception
-    {
-        new TestingServer(2181);
-
-        String configurationSource = Resources.toString(Resources.getResource("configuration/test.json"), Charset.defaultCharset());
-        CuratorProjectionServer.main(new String[]{configurationSource});
-    }
-}

http://git-wip-us.apache.org/repos/asf/curator/blob/78460f90/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/configuration/TestConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/configuration/TestConfigurationBuilder.java b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/configuration/TestConfigurationBuilder.java
deleted file mode 100644
index 4ecec35..0000000
--- a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/configuration/TestConfigurationBuilder.java
+++ /dev/null
@@ -1,83 +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.rpc.configuration;
-
-import ch.qos.logback.classic.Level;
-import com.google.common.collect.Sets;
-import com.google.common.io.Resources;
-import io.airlift.units.Duration;
-import io.dropwizard.logging.AppenderFactory;
-import org.apache.curator.retry.ExponentialBackoffRetry;
-import org.apache.curator.retry.RetryNTimes;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-public class TestConfigurationBuilder
-{
-    @Test
-    public void testSimple() throws Exception
-    {
-        Configuration configuration = loadTestConfiguration("configuration/simple.json");
-        Assert.assertEquals(configuration.getThrift().getPort(), 1234);
-        Assert.assertEquals(configuration.getPingTime(), new Duration(10, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testLogging() throws Exception
-    {
-        Configuration configuration = loadTestConfiguration("configuration/logging.json");
-        Assert.assertEquals(configuration.getLogging().getLevel(), Level.INFO);
-        Assert.assertEquals(configuration.getLogging().getAppenders().size(), 2);
-
-        Set<String> types = Sets.newHashSet();
-        for ( AppenderFactory appenderFactory : configuration.getLogging().getAppenders() )
-        {
-            types.add(appenderFactory.getClass().getSimpleName());
-        }
-        Assert.assertEquals(types, Sets.newHashSet("FileAppenderFactory", "ConsoleAppenderFactory"));
-    }
-
-    @Test
-    public void testConnections() throws Exception
-    {
-        Configuration configuration = loadTestConfiguration("configuration/connections.json");
-        Assert.assertEquals(configuration.getConnections().size(), 2);
-
-        Assert.assertEquals(configuration.getConnections().get(0).getName(), "test");
-        Assert.assertEquals(configuration.getConnections().get(0).getConnectionString(), "one:1,two:2");
-        Assert.assertEquals(configuration.getConnections().get(0).getConnectionTimeout(), new Duration(20, TimeUnit.SECONDS));
-        Assert.assertEquals(configuration.getConnections().get(0).getRetry().build().getClass(), ExponentialBackoffRetry.class);
-
-        Assert.assertEquals(configuration.getConnections().get(1).getName(), "alt");
-        Assert.assertEquals(configuration.getConnections().get(1).getConnectionString(), "three:3,four:4");
-        Assert.assertEquals(configuration.getConnections().get(1).getConnectionTimeout(), new Duration(30, TimeUnit.SECONDS));
-        Assert.assertEquals(configuration.getConnections().get(1).getRetry().build().getClass(), RetryNTimes.class);
-    }
-
-    private Configuration loadTestConfiguration(String name) throws Exception
-    {
-        URL resource = Resources.getResource(name);
-        String source = Resources.toString(resource, Charset.defaultCharset());
-        return new ConfigurationBuilder(source).build();
-    }
-}


[3/3] git commit: wip on doc

Posted by ra...@apache.org.
wip on doc


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

Branch: refs/heads/curator-rpc
Commit: bfc388ce020afa62a6f5e1d6bd3c6cdd9a82e8a3
Parents: 48b0759
Author: randgalt <ra...@apache.org>
Authored: Sun Jun 1 13:14:49 2014 -0500
Committer: randgalt <ra...@apache.org>
Committed: Sun Jun 1 13:14:49 2014 -0500

----------------------------------------------------------------------
 .../idl/services/CuratorProjectionService.java  | 15 ++++
 .../src/site/confluence/events.confluence       | 85 ++++++++++++++++++++
 2 files changed, 100 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/bfc388ce/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
index ca5a604..b9de507 100644
--- a/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
+++ b/curator-x-rpc/src/main/java/org/apache/curator/x/rpc/idl/services/CuratorProjectionService.java
@@ -314,6 +314,21 @@ public class CuratorProjectionService
     }
 
     @ThriftMethod
+    public void sync(CuratorProjection projection, String path, String asyncContext) throws RpcException
+    {
+        try
+        {
+            CuratorEntry entry = CuratorEntry.mustGetEntry(connectionManager, projection);
+            BackgroundCallback backgroundCallback = new RpcBackgroundCallback(this, projection);
+            entry.getClient().sync().inBackground(backgroundCallback, asyncContext).forPath(path);
+        }
+        catch ( Exception e )
+        {
+            throw new RpcException(e);
+        }
+    }
+
+    @ThriftMethod
     public boolean closeGenericProjection(CuratorProjection projection, String id) throws RpcException
     {
         try

http://git-wip-us.apache.org/repos/asf/curator/blob/bfc388ce/curator-x-rpc/src/site/confluence/events.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/events.confluence b/curator-x-rpc/src/site/confluence/events.confluence
index 416b978..a6df4e8 100644
--- a/curator-x-rpc/src/site/confluence/events.confluence
+++ b/curator-x-rpc/src/site/confluence/events.confluence
@@ -2,3 +2,88 @@
 
 h1. Events
 
+
+h2. Event Loop
+
+In order to receive out\-of\-bounds messages (connection state changes, watcher triggers, etc.) you must have an event loop to recieve
+messages from the EventService. Here is pseudo code:
+
+{code}
+inThread => {
+    while ( isOpen ) {
+        event = eventService.getNextEvent(curatorProjection)
+        ... process event ...
+    }
+}
+{code}
+
+h2. Schema
+
+h3. CuratorEvent
+
+||Field||Type||Description||
+|type|CuratorEventType|The event type|
+|resultCode|int|some event types have a result code (i.e. async API calls)|
+|path|string|if there is a path associated with the event|
+|context|string|async context for async API calls|
+|stat|Stat|some event types have a ZooKeeper Stat object|
+|data|bytes|ZNode data if the event type has it|
+|name|string|ZNode name if the event type has it|
+|children|list of string|list of node names if the event type has it|
+|aclList|list of Acl|list of ACL data if the event type has it|
+|watchedEvent|WatchedEvent|if the event type is WATCHED|
+|leaderEvent|LeaderEvent|if the event type is WATCHED|
+|childrenCacheEvent|PathChildrenCacheEvent|if the event type is PATH\_CHILDREN\_CACHE|
+
+h3. CuratorEventType
+
+||Value||Description||
+|PING|Returned if there no events have been generated within the [[configured|configuration.html]] pingTime|
+|CREATE|Async createNode() API completion|
+|DELETE|Async deleteNode() API completion|
+|EXISTS|Async exists() API completion|
+|GET\_DATA|Async getData() API completion|
+|SET\_DATA|Async setData() API completion|
+|CHILDREN|Async getChildren() API completion|
+|SYNC|Async sync() API completion|
+|WATCHED|A watcher has triggered|
+|CONNECTION\_CONNECTED|A Curator ConnectionStateListener is installed. This event is for the initial successful connection.|
+|CONNECTION\_SUSPENDED|A Curator ConnectionStateListener is installed. This event means the connection has been suspended.|
+|CONNECTION\_RECONNECTED|A Curator ConnectionStateListener is installed. This event means the connection has been reconnected.|
+|CONNECTION\_LOST|A Curator ConnectionStateListener is installed. This event means the connection has been lost.|
+|CONNECTION\_READ\_ONLY|A Curator ConnectionStateListener is installed. This event means the connection has changed to read only.|
+|LEADER|A Leader recipe event|
+|PATH\_CHILDREN\_CACHE|A path children cache event|
+|NODE\_CACHE|The node for a node cache has changed|
+
+h3. LeaderEvent
+
+||Field||Type||Description||
+|path|string|The leader's path|
+|participantId|string|The participant ID for the event being reported|
+|isLeader|bool|if true, this participant is being made leader. If false, it is losing leadership.|
+
+h3. PathChildrenCacheEvent
+
+||Field||Type||Description||
+|cachedPath|name|The path being cached|
+|type|PathChildrenCacheEventType|cache event type|
+|data|ChildData|data for the child ZNode|
+
+h3. PathChildrenCacheEventType
+
+Values:     CHILD\_ADDED,
+            CHILD\_UPDATED,
+            CHILD\_REMOVED,
+            CONNECTION\_SUSPENDED,
+            CONNECTION\_RECONNECTED,
+            CONNECTION\_LOST,
+            INITIALIZED
+
+h3. ChildData
+
+||Field||Type||Description||
+|path|string|The ZNode path|
+|stat|Stat|ZooKeeper Stat object|
+|data|bytes|ZNode data (if the cache is configured to cache data)|
+


[2/3] git commit: wip on doc

Posted by ra...@apache.org.
wip on doc


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

Branch: refs/heads/curator-rpc
Commit: 48b0759b735a889a12f421994f051616b5c62248
Parents: 78460f9
Author: randgalt <ra...@apache.org>
Authored: Sun Jun 1 12:52:55 2014 -0500
Committer: randgalt <ra...@apache.org>
Committed: Sun Jun 1 12:52:55 2014 -0500

----------------------------------------------------------------------
 .../src/site/confluence/deploy.confluence       |   4 +-
 .../src/site/confluence/events.confluence       |   4 +
 .../src/site/confluence/index.confluence        |   6 +-
 .../src/site/confluence/usage.confluence        |  85 +++++++++-
 .../org/apache/curator/x/rpc/TestClient.java    | 167 +++++++++++++++++++
 .../org/apache/curator/x/rpc/TestServer.java    |  34 ++++
 6 files changed, 294 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/48b0759b/curator-x-rpc/src/site/confluence/deploy.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/deploy.confluence b/curator-x-rpc/src/site/confluence/deploy.confluence
index af3b682..8c93cb8 100644
--- a/curator-x-rpc/src/site/confluence/deploy.confluence
+++ b/curator-x-rpc/src/site/confluence/deploy.confluence
@@ -11,13 +11,13 @@ Curator RPC is built as an "uber" Java JAR and can be downloaded from Maven Cent
 java -jar curator-x-rpc-VERSION.jar <argument>
 {noformat}
 
-The argument is either a configuration file or a JSON or YAML string. See [[Configuration|configuration.html]] for details.
+The argument is either a configuration file or a JSON or YAML string. Call without the argument for help text. See [[Configuration|configuration.html]] for details.
 
 h2. Deploying
 
 Curator RPC is designed to have an instance of its Thrift Server co\-located on each client instance that needs to connect to ZooKeeper
 (see the figure below). Each Curator RPC instance is configured (see [[Configuration|configuration.html]]) to connect to one or more
-ZooKeeper clusters. The Curator Framework instances are maintained inside of the Curator RPC instances and RPC clients reference these instances by ID.
+ZooKeeper clusters. The Curator Framework instances are maintained inside of the Curator RPC instances and RPC clients reference these instances by name.
 
 How you configure your server to launch depends on your environment and other needs. Here are some suggestions:
 

http://git-wip-us.apache.org/repos/asf/curator/blob/48b0759b/curator-x-rpc/src/site/confluence/events.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/events.confluence b/curator-x-rpc/src/site/confluence/events.confluence
new file mode 100644
index 0000000..416b978
--- /dev/null
+++ b/curator-x-rpc/src/site/confluence/events.confluence
@@ -0,0 +1,4 @@
+[[Curator RPC Proxy|index.html]] / Events
+
+h1. Events
+

http://git-wip-us.apache.org/repos/asf/curator/blob/48b0759b/curator-x-rpc/src/site/confluence/index.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/index.confluence b/curator-x-rpc/src/site/confluence/index.confluence
index f29aff9..962a3e1 100644
--- a/curator-x-rpc/src/site/confluence/index.confluence
+++ b/curator-x-rpc/src/site/confluence/index.confluence
@@ -29,4 +29,8 @@ See the [[Usage Page|usage.html]] for details on using the RPC proxy.
 
 h2. Configuration
 
-See the [[Configuration|configuration.html]] for details on configuring the RPC proxy.
+See [[Configuration|configuration.html]] for details on configuring the RPC proxy.
+
+h2. Events
+
+See [[Events|events.html]] for details on the Curator RPC event loop and its structure.

http://git-wip-us.apache.org/repos/asf/curator/blob/48b0759b/curator-x-rpc/src/site/confluence/usage.confluence
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/site/confluence/usage.confluence b/curator-x-rpc/src/site/confluence/usage.confluence
index a20c13f..9ddaf97 100644
--- a/curator-x-rpc/src/site/confluence/usage.confluence
+++ b/curator-x-rpc/src/site/confluence/usage.confluence
@@ -18,10 +18,89 @@ Three Thrift Services are included with the Curator RPC:
 
 ||Service||Description||
 |CuratorService|The main service for accessing the Curator APIs and recipes|
-|EventService|Used to receive out-of-band messages for callbacks, watchers, etc|
+|EventService|Used to receive out\-of\-band messages for callbacks, watchers, etc. See [Events|events.html] for details.|
 |DiscoveryService|Curator's ServiceDiscovery recipe|
 
 h2. Concepts
 
-_Projections - Many of the Curator RPC APIs refer to "projections" (e.g. CuratorProjection). A projection is an id that refers
-to a real object instance inside of the RPC server.
+h4. Projections
+
+Many of the Curator RPC APIs refer to "projections" (e.g. CuratorProjection). A projection is an id that refers
+to a real object instance inside of the RPC server. The projection is a "handle" or "cookie" that directly refers to that instance.
+
+h4. Thrift Client Equals a Thread
+
+It's important to remember that each thrift client is the equivalent of a system thread. i.e. you cannot have multiple outstanding
+calls in multiple threads with a given client. For each thread, you should allocate a separate client. A Thrift Client maps directly
+to a single TCP/IP socket.
+
+h4. Event Loop
+
+You must dedicate a separate thread for getting events via the Curator RPC [EventService|events.html]. Curator will report async results,
+connection state changes, watcher triggers, etc. via this event loop.
+
+h4. CuratorProjection Expiration
+
+If you don't make an API call using a CuratorProjection within the [configured timeout|configuration.html] the projection instance
+will be closed and any open recipes, etc. associated with it will be closed. NOTE: calls to the EventService will cause the
+CuratorProjection to be "touched". So, as long as your event loop is running your CuratorProjection instance will be kept open.
+
+h2. Initialization
+
+After setting up Thrift, create a connection to the CuratorService and the EventService. If you plan on using Curator Discovery, create a connection
+to DiscoveryService. Allocate a CuratorProjection instance and then start a thread watching events for that instance. Here is pseudo code:
+
+{code}
+CuratorService.Client curatorService = new CuratorService.Client()
+EventService.Client eventService = new EventService.Client()
+
+curatorProjection = curatorService.newCuratorProjection(name)
+
+inThread => {
+    while ( isOpen ) {
+        event = eventService.getNextEvent(curatorProjection)
+        ... process event ...
+    }
+}
+{code}
+
+h2. Usage
+
+Once initialized, use recipes/APIs as needed. Here is an example of using the lock recipe:
+
+{code}
+lockId = client.acquireLock(curatorProjection, "/mylock", 10000);
+if lockId.id == null {
+    // lock attempt failed. Throw exception, etc.
+}
+
+// you now own the lock
+
+client.closeGenericProjection(curatorProjection, lockId.id);
+{code}
+
+Here is an example of using the path cache:
+
+{code}
+cacheProjection = client.startPathChildrenCache(curatorProjection, "/path", true, false, BUILD_INITIAL_CACHE)
+
+...
+
+data = client.getPathChildrenCacheDataForPath(curatorProjection, cacheProjection, "/path/child");
+
+...
+
+// in your event loop, you will get events for the cache. e.g.
+event = eventService.getNextEvent(curatorProjection)
+if event.type == PATH_CHILDREN_CACHE {
+    if event.childrenCacheEvent.type == CHILD_UPDATED {
+        // node described by event.childrenCacheEvent.data has changed
+        // event.childrenCacheEvent.cachedPath is the path that was passed to startPathChildrenCache()
+    }
+}
+
+...
+
+// when done with the cache, close it
+client.closeGenericProjection(curatorProjection, cacheProjection.id);
+{code}

http://git-wip-us.apache.org/repos/asf/curator/blob/48b0759b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java
new file mode 100644
index 0000000..43a2ffc
--- /dev/null
+++ b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestClient.java
@@ -0,0 +1,167 @@
+/**
+ * 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.rpc;
+
+import org.apache.curator.generated.*;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TSocket;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Executors;
+
+public class TestClient
+{
+    public static void main(String[] args) throws Exception
+    {
+        TSocket clientTransport = new TSocket("localhost", 8899);
+        clientTransport.open();
+        TProtocol clientProtocol = new TBinaryProtocol(clientTransport);
+        final CuratorService.Client client = new CuratorService.Client(clientProtocol);
+
+        TSocket eventTransport = new TSocket("localhost", 8899);
+        eventTransport.open();
+        TProtocol eventProtocol = new TBinaryProtocol(eventTransport);
+        final EventService.Client serviceClient = new EventService.Client(eventProtocol);
+
+        TSocket discoveryTransport = new TSocket("localhost", 8899);
+        discoveryTransport.open();
+        TProtocol discoveryProtocol = new TBinaryProtocol(discoveryTransport);
+        final DiscoveryService.Client discoveryClient = new DiscoveryService.Client(discoveryProtocol);
+
+        final CuratorProjection curatorProjection = client.newCuratorProjection("test");
+
+        Executors.newSingleThreadExecutor().submit
+        (
+            new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    try
+                    {
+                        //noinspection InfiniteLoopStatement
+                        for(;;)
+                        {
+                            CuratorEvent nextEvent = serviceClient.getNextEvent(curatorProjection);
+                            System.out.println(nextEvent);
+                        }
+                    }
+                    catch ( TException e )
+                    {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        );
+
+        CreateSpec createSpec = new CreateSpec();
+        createSpec.path = "/this/should/fail";
+        createSpec.data = ByteBuffer.wrap("hey".getBytes());
+        try
+        {
+            client.createNode(curatorProjection, createSpec);
+        }
+        catch ( CuratorException e )
+        {
+            System.out.println("Ex: " + e);
+        }
+
+        createSpec = new CreateSpec();
+        createSpec.path = "/a/b/c";
+        createSpec.creatingParentsIfNeeded = true;
+        createSpec.data = ByteBuffer.wrap("hey".getBytes());
+        OptionalPath path = client.createNode(curatorProjection, createSpec);
+        System.out.println("Path: " + path);
+
+        PathChildrenCacheProjection pathChildrenCacheProjection = client.startPathChildrenCache(curatorProjection, "/a/b", true, false, PathChildrenCacheStartMode.BUILD_INITIAL_CACHE);
+
+        NodeCacheProjection nodeCache = client.startNodeCache(curatorProjection, "/a/b/c", false, true);
+        ChildData nodeCacheData = client.getNodeCacheData(curatorProjection, nodeCache);
+        System.out.println("nodeCacheData: " + nodeCacheData);
+
+        List<ChildData> pathChildrenCacheData = client.getPathChildrenCacheData(curatorProjection, pathChildrenCacheProjection);
+        System.out.println("Child data: " + pathChildrenCacheData);
+
+        GetChildrenSpec getChildrenSpec = new GetChildrenSpec();
+        getChildrenSpec.path = "/a";
+        OptionalChildrenList children = client.getChildren(curatorProjection, getChildrenSpec);
+        System.out.println("Children: " + children);
+
+        ChildData pathChildrenCacheDataForPath = client.getPathChildrenCacheDataForPath(curatorProjection, pathChildrenCacheProjection, "/a/b/c");
+        System.out.println(pathChildrenCacheDataForPath);
+
+        LockProjection lockId = client.acquireLock(curatorProjection, "/mylock", 1000);
+        client.closeGenericProjection(curatorProjection, lockId.id);
+
+        GetDataSpec getDataSpec = new GetDataSpec();
+        getDataSpec.watched = true;
+        getDataSpec.path = "/a/b/c";
+        ByteBuffer data = client.getData(curatorProjection, getDataSpec);
+        System.out.println("getData: " + new String(data.array()));
+
+        ExistsSpec existsSpec = new ExistsSpec();
+        existsSpec.path = "/a/b/c";
+        System.out.println("exists: " + client.exists(curatorProjection, existsSpec));
+
+        DeleteSpec deleteSpec = new DeleteSpec();
+        deleteSpec.path = "/a/b/c";
+        client.deleteNode(curatorProjection, deleteSpec);
+
+        System.out.println("exists: " + client.exists(curatorProjection, existsSpec));
+
+        LeaderResult leader = client.startLeaderSelector(curatorProjection, "/leader", "me", 10000);
+        System.out.println("Has Leader: " + leader.hasLeadership);
+
+        List<Participant> leaderParticipants = client.getLeaderParticipants(curatorProjection, leader.projection);
+        System.out.println("Participants: " + leaderParticipants);
+
+        boolean isLeader = client.isLeader(curatorProjection, leader.projection);
+        System.out.println("isLeader: " + isLeader);
+
+        client.closeGenericProjection(curatorProjection, leader.projection.id);
+
+        pathChildrenCacheData = client.getPathChildrenCacheData(curatorProjection, pathChildrenCacheProjection);
+        System.out.println("Child data: " + pathChildrenCacheData);
+
+        nodeCacheData = client.getNodeCacheData(curatorProjection, nodeCache);
+        System.out.println("nodeCacheData: " + nodeCacheData);
+
+        PersistentEphemeralNodeProjection node = client.startPersistentEphemeralNode(curatorProjection, "/my/path", ByteBuffer.wrap("hey".getBytes()), PersistentEphemeralNodeMode.EPHEMERAL);
+        existsSpec.path = "/my/path";
+        OptionalStat nodeExists = client.exists(curatorProjection, existsSpec);
+        System.out.println("nodeExists: " + nodeExists);
+        client.closeGenericProjection(curatorProjection, node.id);
+
+        List<LeaseProjection> leaseProjections = client.startSemaphore(curatorProjection, "/semi", 3, 1000, 10);
+        System.out.println("leaseProjections: " + leaseProjections);
+        for ( LeaseProjection leaseProjection : leaseProjections )
+        {
+            client.closeGenericProjection(curatorProjection, leaseProjection.id);
+        }
+
+        DiscoveryInstance yourInstance = discoveryClient.makeDiscoveryInstance("mine", ByteBuffer.wrap(new byte[]{}), 8080);
+        DiscoveryProjection discovery = discoveryClient.startDiscovery(curatorProjection, "/discovery", yourInstance);
+        DiscoveryProviderProjection provider = discoveryClient.startProvider(curatorProjection, discovery, "mine", ProviderStrategyType.ROUND_ROBIN, 1000, 3);
+
+        DiscoveryInstance instance = discoveryClient.getInstance(curatorProjection, provider);
+        System.out.println("Instance: " + instance);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/48b0759b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java
----------------------------------------------------------------------
diff --git a/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java
new file mode 100644
index 0000000..3564777
--- /dev/null
+++ b/curator-x-rpc/src/test/java/org/apache/curator/x/rpc/TestServer.java
@@ -0,0 +1,34 @@
+/**
+ * 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.rpc;
+
+import com.google.common.io.Resources;
+import org.apache.curator.test.TestingServer;
+import java.nio.charset.Charset;
+
+public class TestServer
+{
+    public static void main(String[] args) throws Exception
+    {
+        new TestingServer(2181);
+
+        String configurationSource = Resources.toString(Resources.getResource("configuration/test.json"), Charset.defaultCharset());
+        CuratorProjectionServer.main(new String[]{configurationSource});
+    }
+}