Exploring Apache ZooKeeper :: Part-2


Bhaskar S 05/24/2014


Overview

In Part-1 we laid out the basic concepts of ZooKeeper and got our hands dirty with ZooKeeper primitives using the command-line interface.

In this part, we will implement the same primitives using the ZooKeeper Java API.

Hands-on with ZooKeeper Java API

ZooKeeper Connection

The main class that defines all the ZooKeeper primitives is the class org.apache.zookeeper.ZooKeeper.

The first step for any client to use the ZooKeeper is to establish a connection with the ensemble.

The following Java code snippet shows how to connect to an ensemble:

Listing.1
    final static ZooKeeper connect(String hostPortList, int sessionTimeout)
        throws Exception {
        CountDownLatch signal = new CountDownLatch(1);
        
        ZooKeeper zk = new ZooKeeper(hostPortList, sessionTimeout, (WatchedEvent event) -> {
            if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                log.info("ZK[" + hostPortList + "] -> Connected !!!");
                signal.countDown();
            }
        });
        
        signal.await();
        
        return zk;
    }

To connect to the ensemble and establish a ZooKeeper session, we instantiate a org.apache.zookeeper.ZooKeeper object.

The first parameter is the connection string which is a comma separated list of host:port pairs for each of the ZooKeeper servers in the ensemble.

The second parameter is the session timeout in milliseconds.

The third parameter is an object of type org.apache.zookeeper.Watcher that behaves like a notification (callback) mechanism.

Connection to the ensemble is established in an asynchronous manner. The call to the org.apache.zookeeper.ZooKeeper constructor will return immediately. When the connection is established with one of the servers in the the ensemble, we are notified via the specified org.apache.zookeeper.Watcher.

ZNode Creation

To create a znode (be it persistent or ephemeral) in the ZooKeeper namespace, invoke the create() method on the org.apache.zookeeper.ZooKeeper object.

The following Java code snippet shows how to create a znode via a synchronous blocking call:

Listing.2
    final static boolean createZnode(ZooKeeper zk, CreateMode mode, String path, byte[] data) {
        boolean success = false;
        
        try {
            zk.create(path,
                      data,
                      ZooDefs.Ids.OPEN_ACL_UNSAFE,
                      mode);
            success = true;
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("createZnode: Exception", ex);
        }
        
        return success;
    }

The synchronous version of the create() call takes four parameters.

The first parameter is the path to the znode.

The second parameter is the data as a byte array.

The third parameter is an interface of type org.apache.zookeeper.ZooDefs which defines a set of access control list (ACL). The ACL ZooDefs.Ids.OPEN_ACL_UNSAFE allows anyone to access the znode without any restrictions.

The fourth parameter is an enum of type org.apache.zookeeper.CreateMode that indicates the type of the znode - persistent or ephemeral.

The following Java code snippet shows how to create a znode via an asynchronous version of the call:

Listing.3
    final static boolean asyncCreateZnode(ZooKeeper zk, CreateMode mode, String path, byte[] data) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class CreateZnodeContext {
            boolean success = false;
            CreateMode type;
            byte[] data;

            CreateZnodeContext(CreateMode type, byte[] data) {
                this.type = type;
                this.data = data;
            }
            
            void setSuccess() {
                success = true;
            }
        }
        
        final CreateZnodeContext ctx = new CreateZnodeContext(mode, data);
        
        class CreateZnodeStringCallback implements StringCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, String name) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((CreateZnodeContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Created !!!");
                        signal.countDown();
                        break;
                    }
                    case NODEEXISTS:
                    {
                        log.info("ZK[" + path + "] -> Already Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Will Retry !!!");
                        try {
                            zk.create(path,
                                      ((CreateZnodeContext)ctx).data,
                                      ZooDefs.Ids.OPEN_ACL_UNSAFE,
                                      ((CreateZnodeContext)ctx).type,
                                      new CreateZnodeStringCallback(),
                                      ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncCreateZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.create(path,
                  ctx.data,
                  ZooDefs.Ids.OPEN_ACL_UNSAFE,
                  ctx.type,
                  new CreateZnodeStringCallback(),
                  ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }

The asynchronous version of the create() call takes six parameters.

The first parameter is the path to the znode.

The second parameter is the data as a byte array.

The third parameter is an interface of type org.apache.zookeeper.ZooDefs which defines a set of access control list (ACL). The ACL ZooDefs.Ids.OPEN_ACL_UNSAFE allows anyone to access the znode without any restrictions.

The fourth parameter is an enum of type org.apache.zookeeper.CreateMode that indicates the type of the znode - persistent or ephemeral.

The fifth parameter is a notification object of type org.apache.zookeeper.AsyncCallback.StringCallback. The result (success or failure) of the creation of the znode is notified via a call to the processResult() method.

The sixth parameter is a user defined context object which when specified will be returned in the notification call to processResult().

In our case, we have defined both the context object and the notification callback as inner classes inside the method.

ZNode Existence

To check if a znode (be it persistent or ephemeral) is present in the ZooKeeper namespace, invoke the exists() method on the org.apache.zookeeper.ZooKeeper object.

The following Java code snippet shows how to check for the existence of a znode via a synchronous blocking call:

Listing.4
    final static boolean checkZnode(ZooKeeper zk, String path, Watcher watcher) {
        boolean success = false;
        
        try {
            Stat stat = zk.exists(path,
                                  watcher);
            if (stat != null) {
                success = true;
                log.info("ZK[" + path + "] -> Exists, Stat: {ctime = " + new Date(stat.getCtime())
                    + ", mtime = " + new Date(stat.getMtime())
                    + ", version = " + stat.getVersion() + "}");
            }
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("checkZnode: Exception", ex);
        }
        
        return success;
    }

The synchronous version of the exists() call takes two parameters.

The first parameter is the path to the znode.

The second parameter is an instance of org.apache.zookeeper.Watcher. Whenever the data associated with the znode changes, we get a callback on the watcher.

The following Java code snippet shows how to check for the existence of a znode via an asynchronous version of the call:

Listing.5
    final static boolean asyncCheckZnode(ZooKeeper zk, String path, Watcher watcher) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class CheckZnodeContext {
            boolean success = false;
            
            void setSuccess() {
                success = true;
            }
        }
        
        final CheckZnodeContext ctx = new CheckZnodeContext();
        
        class CheckZnodeStatCallback implements StatCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((CheckZnodeContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Exists, Stat: {ctime = " + new Date(stat.getCtime())
                            + ", mtime = " + new Date(stat.getMtime())
                            + ", version = " + stat.getVersion() + "}");
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.exists(path,
                                      watcher,
                                      new CheckZnodeStatCallback(),
                                      ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncCheckZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.exists(path,
                  watcher,
                  new CheckZnodeStatCallback(),
                  ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }

The asynchronous version of the exists() call takes four parameters.

The first parameter is the path to the znode.

The second parameter is an instance of org.apache.zookeeper.Watcher.

The third parameter is a notification object of type org.apache.zookeeper.AsyncCallback.StatCallback. The result (success or failure) of the check for existence of the znode is notified via a call to the processResult() method. The org.apache.zookeeper.data.Stat object encapsulates the metadata information associated with a znode.

The fourth parameter is a user defined context object which when specified will be returned in the notification call to processResult().

In our case, we have defined both the context object and the notification callback as inner classes inside the method.

ZNode Get Children

To get all the children znodes under a given znode in the ZooKeeper namespace, invoke the getChildren() method on the org.apache.zookeeper.ZooKeeper object.

The following Java code snippet shows how to fetch all the children under a znode via a synchronous blocking call:

Listing.6
    final static List<String> getZnodeChildren(ZooKeeper zk, String path, Watcher watcher) {
        List<String> children = null;
        
        try {
            children = zk.getChildren(path,
                                      watcher);
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("getZnodeChildren: Exception", ex);
        }
        
        return children;
    }

The synchronous version of the getChildren() call takes two parameters.

The first parameter is the path to the znode.

The second parameter is an instance of org.apache.zookeeper.Watcher. Whenever the children under the znode change (created or deleted), we get a callback on the watcher.

The following Java code snippet shows how to fetch all the children under a znode via an asynchronous version of the call:

Listing.7
    final static List<String> asyncGetZnodeChildren(ZooKeeper zk, String path, Watcher watcher) {
        CountDownLatch signal = new CountDownLatch(1);
        
        final List<String> children = new ArrayList<>();
        
        class GetZnodeChildrenCallback implements ChildrenCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, List<String> list) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        if (list != null) {
                            children.addAll(list);
                        }
                        log.info("ZK[" + path + "] -> Children: " + list);
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.getChildren(path,
                                           watcher,
                                           new GetZnodeChildrenCallback(),
                                           null);
                        }
                        catch (Exception ex) {
                            log.error("asyncGetZnodeChildren: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.getChildren(path,
                       watcher,
                       new GetZnodeChildrenCallback(),
                       null);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return children;
    }

The asynchronous version of the getChildren() call takes four parameters.

The first parameter is the path to the znode.

The second parameter is an instance of org.apache.zookeeper.Watcher.

The third parameter is a notification object of type org.apache.zookeeper.AsyncCallback.ChildrenCallback. The result (success or failure) of the operation to get all the children under znode is notified via a call to the processResult() method.

The fourth parameter is a user defined context object which when specified will be returned in the notification call to processResult().

In this case, we do not have a context object and have the notification callback as inner class inside the method.

ZNode Get Data

To get the data associated with a znode in the ZooKeeper namespace, invoke the getData() method on the org.apache.zookeeper.ZooKeeper object.

The following Java code snippet shows how to fetch the data associated with a znode via a synchronous blocking call:

Listing.8
    final static String getDataZnode(ZooKeeper zk, String path) {
        String data = null;
        
        try {
            Stat stat = new Stat();
            
            byte[] ba = zk.getData(path,
                                   false,
                                   stat);
            if (ba != null) {
                data = new String(ba);
            }
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("getDataZnode: Exception", ex);
        }
        
        return data;
    }

The synchronous version of the getData() call takes three parameters.

The first parameter is the path to the znode.

The second parameter is a boolean to indicate if we want to watch for any changes to the data associated with the znode.

The third parameter is an instance of org.apache.zookeeper.data.Stat which encapsulates the metadata information of the znode.

The following Java code snippet shows how to fetch the data associated with a znode via an asynchronous version of the call:

Listing.9
    final static String asyncGetDataZnode(ZooKeeper zk, String path) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class GetDataZnodeContext {
            String data = null;
            
            void setData(String data) {
                this.data = data;
            }
        }
        
        final GetDataZnodeContext ctx = new GetDataZnodeContext();
        
        class GetZnodeDataCallback implements DataCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)  {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((GetDataZnodeContext)ctx).setData(new String(data));
                        log.info("ZK[" + path + "] -> Exists, Data = " + new String(data));
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.getData(path,
                                       false,
                                       new GetZnodeDataCallback(),
                                       ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncGetDataZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
    
        zk.getData(path,
                   false,
                   new GetZnodeDataCallback(),
                   ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.data;
    }

The asynchronous version of the getData() call takes four parameters.

The first parameter is the path to the znode.

The second parameter is a boolean to indicate if we want to watch for any changes to the data associated with the znode.

The third parameter is a notification object of type org.apache.zookeeper.AsyncCallback.DataCallback. The result (success or failure) of fetching the data associate with the znode is notified via a call to the processResult() method.

The fourth parameter is a user defined context object which when specified will be returned in the notification call to processResult(). We use the context object as a holder of the data that is returned in the asynchronous call to processResult().

In our case, we have defined both the context object and the notification callback as inner classes inside the method.

ZNode Set Data

To set the data associated with a znode in the ZooKeeper namespace, invoke the setData() method on the org.apache.zookeeper.ZooKeeper object.

The following Java code snippet shows how to change the data associated with a znode via a synchronous blocking call:

Listing.10
    final static boolean setDataZnode(ZooKeeper zk, String path, byte[] data) {
        boolean success = false;
        
        try {
            Stat stat = zk.setData(path,
                                   data,
                                   -1);
            if (stat != null) {
                success = true;
            }
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("setDataZnode: Exception", ex);
        }
        
        return success;
    }

The synchronous version of the setData() call takes three parameters.

The first parameter is the path to the znode.

The second parameter is the data as a byte array.

The third parameter is the matching version from the metadata information of the znode. We use a value of -1 to match any version.

The following Java code snippet shows how to change the data associated with a znode via an asynchronous version of the call:

Listing.11
    final static boolean asyncSetDataZnode(ZooKeeper zk, String path, byte[] data) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class SetZnodeDataContext {
            boolean success = false;
            
            void setSuccess() {
                success = true;
            }
        }
        
        final SetZnodeDataContext ctx = new SetZnodeDataContext();
        
        class SetZnodeDataCallback implements StatCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((SetZnodeDataContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Exists, Stat: {ctime = " + new Date(stat.getCtime())
                            + ", mtime = " + new Date(stat.getMtime())
                            + ", version = " + stat.getVersion() + "}");
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.setData(path,
                                       data,
                                       -1,
                                       new SetZnodeDataCallback(),
                                       ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncSetDataZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
    
        zk.setData(path,
                   data,
                   -1,
                   new SetZnodeDataCallback(),
                   ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }

The asynchronous version of the setData() call takes five parameters.

The first parameter is the path to the znode.

The second parameter is the data as a byte array.

The third parameter is the matching version from the metadata information of the znode. We use a value of -1 to match any version.

The fourth parameter is a notification object of type org.apache.zookeeper.AsyncCallback.StatCallback. The result (success or failure) of changing the data associate with the znode is notified via a call to the processResult() method.

The fifth parameter is a user defined context object which when specified will be returned in the notification call to processResult().

In our case, we have defined both the context object and the notification callback as inner classes inside the method.

ZNode Deletion

To delete a znode (be it persistent or ephemeral) from the ZooKeeper namespace, invoke the delete() method on the org.apache.zookeeper.ZooKeeper object.

The following Java code snippet shows how to delete a znode via a synchronous blocking call:

Listing.12
    final static boolean deleteZnode(ZooKeeper zk, String path) {
        boolean success = false;
        
        try {
            zk.delete(path,
                      -1);
            
            success = true;
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("deleteZnode: Exception", ex);
        }
        
        return success;
    }

The synchronous version of the delete() call takes two parameters.

The first parameter is the path to the znode.

The second parameter is the matching version from the metadata information of the znode. We use a value of -1 to match any version.

The following Java code snippet shows how to delete a znode via an asynchronous version of the call:

Listing.13
    final static boolean asyncDeleteZnode(ZooKeeper zk, String path) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class DeleteZnodeContext {
            boolean success = false;
            
            void setSuccess() {
                success = true;
            }
        }
        
        final DeleteZnodeContext ctx = new DeleteZnodeContext();
        
        class DeleteZnodeVoidCallback implements VoidCallback {
            @Override
            public void processResult(int rc, String path, Object ctx) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((DeleteZnodeContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Deleted !!!");
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.delete(path,
                                      -1,
                                      new DeleteZnodeVoidCallback(),
                                      ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncDeleteZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.delete(path,
                  -1,
                  new DeleteZnodeVoidCallback(),
                  ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }

The asynchronous version of the delete() call takes four parameters.

The first parameter is the path to the znode.

The second parameter is the matching version from the metadata information of the znode. We use a value of -1 to match any version.

The third parameter is a notification object of type org.apache.zookeeper.AsyncCallback.VoidCallback. The result (success or failure) of the deletion of the znode is notified via a call to the processResult() method.

The fourth parameter is a user defined context object which when specified will be returned in the notification call to processResult().

In our case, we have defined both the context object and the notification callback as inner classes inside the method.

The following Java code puts together all the functionality we explored thus far into a helper class called ZkHelper:

Listing.14
/*
 * 
 * Name:   ZkHelper
 * 
 * Author: Bhaskar S
 * 
 * Date:   05/24/2014
 * 
 */

package com.polarsparc.zookeeper;

import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.AsyncCallback.ChildrenCallback;
import org.apache.zookeeper.AsyncCallback.DataCallback;
import org.apache.zookeeper.AsyncCallback.VoidCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;

public final class ZkHelper {
    private static final Logger log = LoggerFactory.getLogger(ZkHelper.class);
    
    // ----- Setup Connection to ZooKeeper -----
    
    final static ZooKeeper connect(String hostPortList, int sessionTimeout)
        throws Exception {
        CountDownLatch signal = new CountDownLatch(1);
        
        ZooKeeper zk = new ZooKeeper(hostPortList, sessionTimeout, (WatchedEvent event) -> {
            if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                log.info("ZK[" + hostPortList + "] -> Connected !!!");
                signal.countDown();
            }
        });
        
        signal.await();
        
        return zk;
    }
    
    // ----- Create a Znode (Persistent or Ephemeral) -----
    
    final static boolean createZnode(ZooKeeper zk, CreateMode mode, String path, byte[] data) {
        boolean success = false;
        
        try {
            zk.create(path,
                      data,
                      ZooDefs.Ids.OPEN_ACL_UNSAFE,
                      mode);
            success = true;
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("createZnode: Exception", ex);
        }
        
        return success;
    }
    
    final static boolean asyncCreateZnode(ZooKeeper zk, CreateMode mode, String path, byte[] data) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class CreateZnodeContext {
            boolean success = false;
            CreateMode type;
            byte[] data;

            CreateZnodeContext(CreateMode type, byte[] data) {
                this.type = type;
                this.data = data;
            }
            
            void setSuccess() {
                success = true;
            }
        }
        
        final CreateZnodeContext ctx = new CreateZnodeContext(mode, data);
        
        class CreateZnodeStringCallback implements StringCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, String name) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((CreateZnodeContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Created !!!");
                        signal.countDown();
                        break;
                    }
                    case NODEEXISTS:
                    {
                        log.info("ZK[" + path + "] -> Already Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Will Retry !!!");
                        try {
                            zk.create(path,
                                      ((CreateZnodeContext)ctx).data,
                                      ZooDefs.Ids.OPEN_ACL_UNSAFE,
                                      ((CreateZnodeContext)ctx).type,
                                      new CreateZnodeStringCallback(),
                                      ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncCreateZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.create(path,
                  ctx.data,
                  ZooDefs.Ids.OPEN_ACL_UNSAFE,
                  ctx.type,
                  new CreateZnodeStringCallback(),
                  ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }
    
    // ----- Check for Znode Existence and Get Stats -----
    
    final static boolean checkZnode(ZooKeeper zk, String path, Watcher watcher) {
        boolean success = false;
        
        try {
            Stat stat = zk.exists(path,
                                  watcher);
            if (stat != null) {
                success = true;
                log.info("ZK[" + path + "] -> Exists, Stat: {ctime = " + new Date(stat.getCtime())
                    + ", mtime = " + new Date(stat.getMtime())
                    + ", version = " + stat.getVersion() + "}");
            }
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("checkZnode: Exception", ex);
        }
        
        return success;
    }
    
    final static boolean asyncCheckZnode(ZooKeeper zk, String path, Watcher watcher) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class CheckZnodeContext {
            boolean success = false;
            
            void setSuccess() {
                success = true;
            }
        }
        
        final CheckZnodeContext ctx = new CheckZnodeContext();
        
        class CheckZnodeStatCallback implements StatCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((CheckZnodeContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Exists, Stat: {ctime = " + new Date(stat.getCtime())
                            + ", mtime = " + new Date(stat.getMtime())
                            + ", version = " + stat.getVersion() + "}");
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.exists(path,
                                      watcher,
                                      new CheckZnodeStatCallback(),
                                      ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncCheckZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.exists(path,
                  watcher,
                  new CheckZnodeStatCallback(),
                  ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }
    
    // ----- Get Children from Existing Znode -----
    
    final static List<String> getZnodeChildren(ZooKeeper zk, String path, Watcher watcher) {
        List<String> children = null;
        
        try {
            children = zk.getChildren(path,
                                      watcher);
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("getZnodeChildren: Exception", ex);
        }
        
        return children;
    }
    
    final static List<String> asyncGetZnodeChildren(ZooKeeper zk, String path, Watcher watcher) {
        CountDownLatch signal = new CountDownLatch(1);
        
        final List<String> children = new ArrayList<>();
        
        class GetZnodeChildrenCallback implements ChildrenCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, List<String> list) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        if (list != null) {
                            children.addAll(list);
                        }
                        log.info("ZK[" + path + "] -> Children: " + list);
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.getChildren(path,
                                           watcher,
                                           new GetZnodeChildrenCallback(),
                                           null);
                        }
                        catch (Exception ex) {
                            log.error("asyncGetZnodeChildren: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.getChildren(path,
                       watcher,
                       new GetZnodeChildrenCallback(),
                       null);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return children;
    }
    
    // ----- Get Data from Existing Znode -----
    
    final static String getDataZnode(ZooKeeper zk, String path) {
        String data = null;
        
        try {
            Stat stat = new Stat();
            
            byte[] ba = zk.getData(path,
                                   false,
                                   stat);
            if (ba != null) {
                data = new String(ba);
            }
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("getDataZnode: Exception", ex);
        }
        
        return data;
    }
    
    final static String asyncGetDataZnode(ZooKeeper zk, String path) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class GetDataZnodeContext {
            String data = null;
            
            void setData(String data) {
                this.data = data;
            }
        }
        
        final GetDataZnodeContext ctx = new GetDataZnodeContext();
        
        class GetZnodeDataCallback implements DataCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)  {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((GetDataZnodeContext)ctx).setData(new String(data));
                        log.info("ZK[" + path + "] -> Exists, Data = " + new String(data));
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.getData(path,
                                       false,
                                       new GetZnodeDataCallback(),
                                       ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncGetDataZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
    
        zk.getData(path,
                   false,
                   new GetZnodeDataCallback(),
                   ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.data;
    }
    
    // ----- Set Data for an Existing Znode -----
    
    final static boolean setDataZnode(ZooKeeper zk, String path, byte[] data) {
        boolean success = false;
        
        try {
            Stat stat = zk.setData(path,
                                   data,
                                   -1);
            if (stat != null) {
                success = true;
            }
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("setDataZnode: Exception", ex);
        }
        
        return success;
    }
    
    final static boolean asyncSetDataZnode(ZooKeeper zk, String path, byte[] data) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class SetZnodeDataContext {
            boolean success = false;
            
            void setSuccess() {
                success = true;
            }
        }
        
        final SetZnodeDataContext ctx = new SetZnodeDataContext();
        
        class SetZnodeDataCallback implements StatCallback {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((SetZnodeDataContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Exists, Stat: {ctime = " + new Date(stat.getCtime())
                            + ", mtime = " + new Date(stat.getMtime())
                            + ", version = " + stat.getVersion() + "}");
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.setData(path,
                                       data,
                                       -1,
                                       new SetZnodeDataCallback(),
                                       ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncSetDataZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
    
        zk.setData(path,
                   data,
                   -1,
                   new SetZnodeDataCallback(),
                   ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }
    
    // ----- Delete an Existing Znode -----
    
    final static boolean deleteZnode(ZooKeeper zk, String path) {
        boolean success = false;
        
        try {
            zk.delete(path,
                      -1);
            
            success = true;
        }
        catch (InterruptedException | KeeperException ex) {
            log.error("deleteZnode: Exception", ex);
        }
        
        return success;
    }
    
    final static boolean asyncDeleteZnode(ZooKeeper zk, String path) {
        CountDownLatch signal = new CountDownLatch(1);
        
        class DeleteZnodeContext {
            boolean success = false;
            
            void setSuccess() {
                success = true;
            }
        }
        
        final DeleteZnodeContext ctx = new DeleteZnodeContext();
        
        class DeleteZnodeVoidCallback implements VoidCallback {
            @Override
            public void processResult(int rc, String path, Object ctx) {
                switch(KeeperException.Code.get(rc)) {
                    case OK:
                    {
                        ((DeleteZnodeContext)ctx).setSuccess();
                        log.info("ZK[" + path + "] -> Deleted !!!");
                        signal.countDown();
                        break;
                    }
                    case NONODE:
                    {
                        log.info("ZK[" + path + "] -> Does not Exists !!!");
                        signal.countDown();
                        break;
                    }
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case SESSIONMOVED:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc));
                        try {
                            zk.delete(path,
                                      -1,
                                      new DeleteZnodeVoidCallback(),
                                      ctx);
                        }
                        catch (Exception ex) {
                            log.error("asyncDeleteZnode: Exception", ex);
                        }
                        break;
                    }
                    default:
                    {
                        log.info("ZK[" + path + "] -> Code = " + KeeperException.Code.get(rc) + ", Failed !!!");
                        signal.countDown();
                        break;
                    }
                }
            }
        }
        
        zk.delete(path,
                  -1,
                  new DeleteZnodeVoidCallback(),
                  ctx);
        
        try {
            signal.await();
        }
        catch (InterruptedException ex) {
        }
        
        return ctx.success;
    }
    
    // ----- Close Connection to ZooKeeper -----
    
    final static void close(ZooKeeper zk)
        throws Exception {
        zk.close();
    }
}

The following Java client tests the synchronous version of the ZooKeeper primitives defined in the class ZkHelper:

Listing.15
/*
 * 
 * Name:   ZNodeTests
 * 
 * Author: Bhaskar S
 * 
 * Date:   05/24/2014
 * 
 */

package com.polarsparc.zookeeper;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.WatchedEvent;

// ----- Usage -----
// java com.polarsparc.zookeeper.ZNodeTests <host-port-list>
//
public class ZNodeTests {
    private static final int SESSION_TIMEOUT = 10000;
    private static final String ppath = "/mytest";
    private static final String spath1 = "/mytest/child-1";
    private static final String spath2 = "/mytest/child-2";
    private static final String tpath = "/mytmp";
    private static final byte[] data = "".getBytes();
    private static final byte[] data2 = "hello".getBytes();
    
    private static final Logger log = LoggerFactory.getLogger(ZNodeTests.class);
    
    // ----- Main Method -----
    
    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.printf("Specify <host-port-list>\n");
            System.exit(1);
        }
        
        try {
            ZooKeeper zk = ZkHelper.connect(args[0], SESSION_TIMEOUT);
            
            boolean status = ZkHelper.createZnode(zk, CreateMode.PERSISTENT, ppath, data);
            
            log.info("Create ZNode " + ppath + " Status = " + status);
            
            status = ZkHelper.checkZnode(zk, ppath, (WatchedEvent event) -> {
                if (event.getType() == Watcher.Event.EventType.NodeDataChanged) {
                    log.info("-----> Data at znode " + event.getPath() + " changed <-----");
                }
            });
            
            log.info("Check ZNode " + ppath + " Status = " + status);
            
            ZkHelper.createZnode(zk, CreateMode.PERSISTENT, spath1, data);
            ZkHelper.createZnode(zk, CreateMode.PERSISTENT, spath2, data);
            
            List<String> children = ZkHelper.getZnodeChildren(zk, ppath, null);
            
            log.info("Get ZNode " + ppath + " Children = " + children);
            
            String str = ZkHelper.getDataZnode(zk, ppath);
            
            log.info("Get ZNode " + ppath + " Data = " + str);
            
            status = ZkHelper.setDataZnode(zk, ppath, data2);
            
            log.info("Set ZNode Data " + ppath + " Status = " + status);
            
            status = ZkHelper.deleteZnode(zk, spath2);
            
            log.info("Delete ZNode " + spath2 + " Status = " + status);
            
            status = ZkHelper.deleteZnode(zk, spath1);
            
            log.info("Delete ZNode " + spath1 + " Status = " + status);
            
            status = ZkHelper.deleteZnode(zk, ppath);
            
            log.info("Delete ZNode " + ppath + " Status = " + status);
            
            status = ZkHelper.createZnode(zk, CreateMode.EPHEMERAL, tpath, data);
            
            log.info("Create ZNode " + tpath + " Status = " + status);
            
            ZkHelper.close(zk);
        }
        catch (Exception ex) {
            log.error("ZNodeTests.main(): Exception", ex);
        }
    }
}

Executing the above Java code will generate the following output:

Output.1

2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:host.name=my-host
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.version=1.8.0_05
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.vendor=Oracle Corporation
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.home=/usr/lib/jvm/java-8-oracle/jre
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.class.path=/home/zkuser/zookeeper/resources:/home/zkuser/zookeeper/lib/jline-0.9.94.jar:/home/zkuser/zookeeper/lib/log4j-1.2.16.jar:/home/zkuser/zookeeper/lib/netty-3.7.0.Final.jar:/home/zkuser/zookeeper/lib/slf4j-api-1.6.1.jar:/home/zkuser/zookeeper/lib/slf4j-log4j12-1.6.1.jar:/home/zkuser/zookeeper/lib/zookeeper-3.4.6.jar:/home/zkuser/zookeeper/build/classes
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.library.path=/usr/lib/jvm/java-8-oracle/jre/lib/amd64:/usr/lib/jvm/java-8-oracle/jre/lib/i386::/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.io.tmpdir=/tmp
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:java.compiler=<NA>
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:os.name=Linux
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:os.arch=amd64
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:os.version=3.13.0-27-generic
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:user.name=zkuser
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:user.home=/home/zkuser
2014-05-24 23:19:17 <main> INFO  ZooKeeper:100 - Client environment:user.dir=/home/zkuser/zookeeper
2014-05-24 23:19:17 <main> INFO  ZooKeeper:438 - Initiating client connection, connectString=192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181 sessionTimeout=10000 watcher=com.polarsparc.zookeeper.ZkHelper$$Lambda$1/758705033@4d76f3f8
2014-05-24 23:19:17 <main-SendThread(192.168.1.1:2181)> INFO  ClientCnxn:975 - Opening socket connection to server 192.168.1.1/192.168.1.1:2181. Will not attempt to authenticate using SASL (unknown error)
2014-05-24 23:19:17 <main-SendThread(192.168.1.1:2181)> INFO  ClientCnxn:852 - Socket connection established to 192.168.1.1/192.168.1.1:2181, initiating session
2014-05-24 23:19:17 <main-SendThread(192.168.1.1:2181)> INFO  ClientCnxn:1235 - Session establishment complete on server 192.168.1.1/192.168.1.1:2181, sessionid = 0x14648a673e00001, negotiated timeout = 10000
2014-05-24 23:19:17 <main-EventThread> INFO  ZkHelper:45 - ZK[192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181] -> Connected !!!
2014-05-24 23:19:17 <main> INFO  ZNodeTests:50 - Create ZNode /mytest Status = true
2014-05-24 23:19:17 <main> INFO  ZkHelper:165 - ZK[/mytest] -> Exists, Stat: {ctime = Sat May 24 23:19:17 EDT 2014, mtime = Sat May 24 23:19:17 EDT 2014, version = 0}
2014-05-24 23:19:17 <main> INFO  ZNodeTests:58 - Check ZNode /mytest Status = true
2014-05-24 23:19:17 <main> INFO  ZNodeTests:65 - Get ZNode /mytest Children = [child-2, child-1]
2014-05-24 23:19:17 <main> INFO  ZNodeTests:69 - Get ZNode /mytest Data = 
2014-05-24 23:19:17 <main-EventThread> INFO  ZNodeTests:54 - -----> Data at znode /mytest changed <-----
2014-05-24 23:19:17 <main> INFO  ZNodeTests:73 - Set ZNode Data /mytest Status = true
2014-05-24 23:19:17 <main> INFO  ZNodeTests:77 - Delete ZNode /mytest/child-2 Status = true
2014-05-24 23:19:17 <main> INFO  ZNodeTests:81 - Delete ZNode /mytest/child-1 Status = true
2014-05-24 23:19:17 <main> INFO  ZNodeTests:85 - Delete ZNode /mytest Status = true
2014-05-24 23:19:17 <main> INFO  ZNodeTests:89 - Create ZNode /mytmp Status = true
2014-05-24 23:19:17 <main> INFO  ZooKeeper:684 - Session: 0x14648a673e00001 closed
2014-05-24 23:19:17 <main-EventThread> INFO  ClientCnxn:512 - EventThread shut down

The following Java client tests the asynchronous version of the ZooKeeper primitives defined in the class ZkHelper:

Listing.16
/*
 * 
 * Name:   ZNodeAsyncTests
 * 
 * Author: Bhaskar S
 * 
 * Date:   05/24/2014
 * 
 */

package com.polarsparc.zookeeper;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.WatchedEvent;

// ----- Usage -----
// java com.polarsparc.zookeeper.ZNodeAsyncTests <host-port-list>
//
public class ZNodeAsyncTests {
    private static final int SESSION_TIMEOUT = 10000;
    private static final String ppath = "/mytest";
    private static final String spath1 = "/mytest/child-1";
    private static final String spath2 = "/mytest/child-2";
    private static final String tpath = "/mytmp";
    private static final byte[] data = "".getBytes();
    private static final byte[] data2 = "hello".getBytes();
    
    private static final Logger log = LoggerFactory.getLogger(ZNodeAsyncTests.class);
    
    // ----- Main Method -----
    
    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.printf("Specify <host-port-list>\n");
            System.exit(1);
        }
        
        try {
            ZooKeeper zk = ZkHelper.connect(args[0], SESSION_TIMEOUT);
            
            boolean status = ZkHelper.asyncCreateZnode(zk, CreateMode.PERSISTENT, ppath, data);
            
            log.info("Create ZNode " + ppath + " Status = " + status);
            
            status = ZkHelper.asyncCheckZnode(zk, ppath, (WatchedEvent event) -> {
                if (event.getType() == Watcher.Event.EventType.NodeDataChanged) {
                    log.info("-----> Data at znode " + event.getPath() + " changed <-----");
                }
            });
            
            log.info("Check ZNode " + ppath + " Status = " + status);
            
            ZkHelper.asyncCreateZnode(zk, CreateMode.PERSISTENT, spath1, data);
            ZkHelper.asyncCreateZnode(zk, CreateMode.PERSISTENT, spath2, data);
            
            List<String> children = ZkHelper.asyncGetZnodeChildren(zk, ppath, null);
            
            log.info("Get ZNode " + ppath + " Children = " + children);
            
            String str = ZkHelper.asyncGetDataZnode(zk, ppath);
            
            log.info("Get ZNode " + ppath + " Data = " + str);
            
            status = ZkHelper.asyncSetDataZnode(zk, ppath, data2);
            
            log.info("Set ZNode Data " + ppath + " Status = " + status);
            
            status = ZkHelper.asyncDeleteZnode(zk, spath2);
            
            log.info("Delete ZNode " + spath2 + " Status = " + status);
            
            status = ZkHelper.asyncDeleteZnode(zk, spath1);
            
            log.info("Delete ZNode " + spath1 + " Status = " + status);
            
            status = ZkHelper.asyncDeleteZnode(zk, ppath);
            
            log.info("Delete ZNode " + ppath + " Status = " + status);
            
            status = ZkHelper.asyncCreateZnode(zk, CreateMode.EPHEMERAL, tpath, data);
            
            log.info("Create ZNode " + tpath + " Status = " + status);
            
            ZkHelper.close(zk);
        }
        catch (Exception ex) {
            log.error("ZNodeAsyncTests.main(): Exception", ex);
        }
    }
}

Executing the above Java code will generate the following output:

Output.2

2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:host.name=my-host
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.version=1.8.0_05
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.vendor=Oracle Corporation
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.home=/usr/lib/jvm/java-8-oracle/jre
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.class.path=/home/zkuser/zookeeper/resources:/home/zkuser/zookeeper/lib/jline-0.9.94.jar:/home/zkuser/zookeeper/lib/log4j-1.2.16.jar:/home/zkuser/zookeeper/lib/netty-3.7.0.Final.jar:/home/zkuser/zookeeper/lib/slf4j-api-1.6.1.jar:/home/zkuser/zookeeper/lib/slf4j-log4j12-1.6.1.jar:/home/zkuser/zookeeper/lib/zookeeper-3.4.6.jar:/home/zkuser/zookeeper/build/classes
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.library.path=/usr/lib/jvm/java-8-oracle/jre/lib/amd64:/usr/lib/jvm/java-8-oracle/jre/lib/i386::/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.io.tmpdir=/tmp
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:java.compiler=<NA>
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:os.name=Linux
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:os.arch=amd64
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:os.version=3.13.0-27-generic
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:user.name=zkuser
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:user.home=/home/zkuser
2014-05-24 23:19:53 <main> INFO  ZooKeeper:100 - Client environment:user.dir=/home/zkuser/zookeeper
2014-05-24 23:19:53 <main> INFO  ZooKeeper:438 - Initiating client connection, connectString=192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181 sessionTimeout=10000 watcher=com.polarsparc.zookeeper.ZkHelper$$Lambda$1/758705033@4d76f3f8
2014-05-24 23:19:53 <main-SendThread(192.168.1.2:2181)> INFO  ClientCnxn:975 - Opening socket connection to server 192.168.1.2/192.168.1.2:2181. Will not attempt to authenticate using SASL (unknown error)
2014-05-24 23:19:53 <main-SendThread(192.168.1.2:2181)> INFO  ClientCnxn:852 - Socket connection established to 192.168.1.2/192.168.1.2:2181, initiating session
2014-05-24 23:19:53 <main-SendThread(192.168.1.2:2181)> INFO  ClientCnxn:1235 - Session establishment complete on server 192.168.1.2/192.168.1.2:2181, sessionid = 0x24648a66eba0000, negotiated timeout = 10000
2014-05-24 23:19:53 <main-EventThread> INFO  ZkHelper:45 - ZK[192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181] -> Connected !!!
2014-05-24 23:19:53 <main-EventThread> INFO  ZkHelper:101 - ZK[/mytest] -> Created !!!
2014-05-24 23:19:53 <main> INFO  ZNodeAsyncTests:50 - Create ZNode /mytest Status = true
2014-05-24 23:19:53 <main-EventThread> INFO  ZkHelper:197 - ZK[/mytest] -> Exists, Stat: {ctime = Sat May 24 23:19:53 EDT 2014, mtime = Sat May 24 23:19:53 EDT 2014, version = 0}
2014-05-24 23:19:53 <main> INFO  ZNodeAsyncTests:58 - Check ZNode /mytest Status = true
2014-05-24 23:19:53 <main-EventThread> INFO  ZkHelper:101 - ZK[/mytest/child-1] -> Created !!!
2014-05-24 23:19:53 <main-EventThread> INFO  ZkHelper:101 - ZK[/mytest/child-2] -> Created !!!
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:279 - ZK[/mytest] -> Children: [child-2, child-1]
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:65 - Get ZNode /mytest Children = [child-2, child-1]
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:371 - ZK[/mytest] -> Exists, Data = 
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:69 - Get ZNode /mytest Data = 
2014-05-24 23:19:54 <main-EventThread> INFO  ZNodeAsyncTests:54 - -----> Data at znode /mytest changed <-----
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:461 - ZK[/mytest] -> Exists, Stat: {ctime = Sat May 24 23:19:54 EDT 2014, mtime = Sat May 24 23:19:54 EDT 2014, version = 1}
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:73 - Set ZNode Data /mytest Status = true
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:553 - ZK[/mytest/child-2] -> Deleted !!!
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:77 - Delete ZNode /mytest/child-2 Status = true
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:553 - ZK[/mytest/child-1] -> Deleted !!!
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:81 - Delete ZNode /mytest/child-1 Status = true
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:553 - ZK[/mytest] -> Deleted !!!
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:85 - Delete ZNode /mytest Status = true
2014-05-24 23:19:54 <main-EventThread> INFO  ZkHelper:101 - ZK[/mytmp] -> Created !!!
2014-05-24 23:19:54 <main> INFO  ZNodeAsyncTests:89 - Create ZNode /mytmp Status = true
2014-05-24 23:19:54 <main> INFO  ZooKeeper:684 - Session: 0x24648a66eba0000 closed
2014-05-24 23:19:54 <main-EventThread> INFO  ClientCnxn:512 - EventThread shut down

References

Exploring Apache ZooKeeper :: Part-1