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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
The following Java client tests the synchronous version of the ZooKeeper
primitives defined in the class ZkHelper:
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:
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