[ Tutorial ] Apache ZooKeeper – Setting ACL in ZooKeeper Client

Now let’s talk about setting the ACL of a znode in ZooKeeper. Before getting into the details, let’s talk more about the scheme and ID.

1. Scheme and ID

ID, as name suggests, is an identifier comprised of a username and password. By default, when the znode has an ACL set accessible by a specific group of users or an individual, the <username>:<password> is first hashed using an SHA-1 hashing algorithm, and then it (hex-string) is base-64 encoded.

As mentioned in earlier blog entries, scheme is like a group of users that are authorized to access a certain znode with a scheme-and-id-specific ACL set.

1.1. World Scheme

World scheme has one ID (anyone). This represents any user in the world.

For example, we type in the following command to set the znode accessible by anyone.

setAcl /newznode world:anyone:crdwa

By doing it correctly, You should get something like this in return:

world_acl_valid

1.2. Auth Scheme

Auth scheme represents a "manually" set group of authenticated users. According to the ZooKeeper documentation (http://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html), auth does not utilize any ID. Unless I am mistaken, this seems not to be the case. Because if you try to set ACL on a znode using auth scheme and not provide any ID, it tells you that is not a valid ID, or some form of ID is needed. Below is a (bad) example:

setAcl /newznode auth:crdwa

as seen above, I did not provide any form of ID. This is what I get:

invalid_acl

A correct way to use this scheme would be as follows:

setAcl /newznode auth:username:password:crdwa

Using auth scheme allows us to have multiple authorized users to access a single znode with the different username and password combination. Say we have 3 users:

username : password
user_123 : pwd_123
user_456 : pwd_456
user_789 : pwd_789

We can use the same syntax above by replacing username with user_123, user_456, or user_789 and password with pwd_123, pwd_456, or pwd_789 respectively.

1.2.1 addauth Command

One important thing to note is you must use the addauth command before proceeding to set the ACL of a znode using the auth scheme. If you try to set the ACL before executing the addauth command, you will get an error as below:

invalid_acl2

Correct way to do is to execute addauth command first, and then execute the setAcl command. Below is the syntax of command execution for addauth:

addauth /<node-name> digest <username>:<password>

By adding the authenticator and setting ACL accordingly, you can ensure that you set the ACL correctly.

valid_acl

Repeat the steps for additional username and password combo, and the ACL for that newznode looks like this:

valid_acl2

1.3. Digest Scheme

Digest scheme represents an individual user with authentication. This uses username:password string that is hashed using the SHA-1 hashing algorithm, and that hashed string is in turn base64 encoded. According to the ZooKeeper website, it is stated that the MD5 hash of <username>:<password> is used as an ACL ID identity. Unless I am mistaken, that seems not to be the case. Instead, what I found was that <username>:<Base64 encoded SHA-1 hash of username:password> is used as an ACL ID (Please see above pictures under the Auth section).

What’s really funny is that if I authenticate an individual user on a znode using digest scheme on ZooKeeper client, instead of storing the username and encoded hash string of <username:password> like it should, it stores a clear, human-readable text of <username:password> as an ID. Executing the addauth command before setting the ACL with digest scheme does not work either. Below is the picture that illustrates my point:

acl_digest

Unless it is easy to work backwards – decoding the user_abc:pwd_abc, and then take that decoded string and undo the SHA-1 hashing part, it turns out setting ACL using digest scheme on a znode in ZooKeeper client is pointless.

Good thing is that if you setAcl a znode using digest scheme via client, you can delete it.

1.4. Host Scheme

Host scheme represents anyone within the same hosting server. I have not done enough with the host scheme yet, but I will come back to this with more details.

1.5. IP Scheme

IP scheme represents any user within the same IP address. Easiest example to use in this case would be 127.0.0.1, which represents the user of that any local machine, since any local machine will have 127.0.0.1 point to the localhost. Below is the syntax of setAcl using IP scheme:

setAcl /<node-name> ip:<IPv4-address>:<permission-set>

Using the syntax above, below is an example using the 127.0.0.1 IP address:

setAcl /newnode ip:127.0.0.1:crdwa

If done correctly, you should get the znode stat like the picture below:

acl_ip

That is it for now. On my next blog post, I will briefly talk about how to access them in Java; furthermore, I will talk more in detail about how username and password are stored. Thanks for reading as usual, and happy zookeeping!

Advertisements

[ Tutorial ] Apache ZooKeeper ACL (Access Control List) Getting Permission Sets

Today, I will talk about the basics of ACL in ZooKeeper and getting the permission sets of ACL.

1. What is ACL?

ACL (Access Control List) is basically an authentication mechanism implemented in ZooKeeper. It makes znodes accessible to users, depending on how it is set. For example, if its scheme is set to world and ID set to anyone, then it is accessible by anyone in the world, thus the world scheme and anyone ID. However, if the scheme is anything other than the world, then it’s a different story. Let’s talk about the basics and its attributes first.

A typical permission set of a znode looks something like this: crdwa. This is actually an acronym (can be in any order) that stands for: Create, Read, Delete, Write, and Admin.

1.1. Getting the ACL of a Znode

To get the ACL of a particular znode, we execute the getAcl command in the ZooKeeper client.

It will return that znode’s ACL in this format:

'[ scheme ],'[ id ]
: [ permission-set ]

Syntax of the getAcl command is: getAcl Path

Example: getAcl /getmyacl

Think of the scheme as more like a specific group of users. The world scheme would represent everyone in the world, literally. There are also different schemes in ZooKeeper, which are digest (individual user with unique username and password), ip, which is an individual or group of users within the same IP address, and host, which is a group of users within the same host.

ID I believe is self-explanatory; should the scheme be world, then ID always has to be anyone. There is no point to restrict specific users if it is meant to be viewed by anyone.

Here, I have an example of getting the ACL of the getmyacl znode. By typing in the command getAcl /getmyacl, you will get something like this:

acl-1

1.2. More About Permission Set

Notice how the permission set says crdwa. If you were trying to get the permission set of a znode in Java, you would get an integer value in return.

First off, you would call getPerms method to get the permission set of a znode in Java. As mentioned earlier, it returns an integer value. In this case, with this znode having a permission set of crdwa, in Java it returns 31, meaning that the user is authorized to create a child znode, read data of that znode, delete that znode, overwrite (or set data) the znode, and has administrative rights of that znode.

Each permission (create, read, delete, write, admin) is actually a bit, either 0 or 1, where 0 represents not allowed, and 1 represents allowed. So, if you convert that 31 into a binary number, you would get 11111. Refer to the following bullet points:

  • Read – 2^0
  • Write – 2^1
  • Create – 2^2
  • Delete – 2^3
  • Admin – 2^4

Say we have a getmyaccl znode. Create, read, and admin are allowed, but delete and write are not. According to my little bullet points above, in Java it would return 21 for the permission set. Convert that to binary, we get 10101 ( (2^4 = 16) + (2^2 = 4) + (2^0 = 1) ) = 21

Let’s try to change its permission set to cwa (create, write, admin) and see what integer value is returned in Java.

This time it returned 22, or 10110 ( (2^4 = 16) + (2^2 = 4) + (2^1 = 2) ) = 22

To get the permission set of a znode, we need to import ACL class (from ZooKeeper package) and ArrayList. First, we need to create an instance of ArrayList that can store ACL object, and create a new instance of ACL object, assign that to the first element of the ArrayList. What’s interesting is that ArrayList contains only one element. Following is the code snippet on how to get the permission set of a znode:

List acl = new ArrayList(); // create new instance of ArrayList to store ACL object
acl = zk.getACL("/getmyacl", stat); 
ACL aclElement = acl.get(0);
System.out.println(aclElement.getPerms()); // for printing the permission set on the screen.  
                                    // this is also how I get 21 and 22 earlier for the permission set.  

When creating a znode the simplest way, any user is authorized the full crdwa permission set. I will talk more about setting the permission set in 2 different blog entries: First one will be the easy; where any user can access the znode. Second one will be tricky (also to talk about and explain), which involves an individual’s username and password, group of users within the same host or the IP address.

This sums up how to get the permission set of a znode. As usual, thanks for reading, and happy zookeeping!

[ Tutorial ] How to Install And Setup Apache ZooKeeper Standalone (Windows)

Today, I will talk about how to install Apache ZooKeeper and run the instance of it.

Prerequisites: JRE 1.6 or higher required (for development purposes, I would install JDK instead 1.6 or higher) At the time of writing this blog, the current stable version of Java is 1.8 and that should work perfectly fine (I have 1.7.0_51)

NOTE: I noticed that some of my peers tend to forget to set the environment variables, so please remember to set them before proceeding.

1. Installing Apache ZooKeeper

1. Download Apache ZooKeeper. You can choose from any given mirror – http://www.apache.org/dyn/closer.cgi/zookeeper/
2. Extract it to where you want to install ZooKeeper. I prefer to save it in the C:\dev\tools directory. Unless you prefer this way as well, you will have to create that directory yourself.
3. Set up the environment variable.

  • To do this, first go to Computer, then click on the System Properties button.
  • image-003

  • Click on the Advanced System Settings link to the left.
  • image-004

  • On a new window pop-up, click on the Environment Variables... button.
  • image-005

  • Under the System Variables section, click New...
  • For the Variable Name, type in ZOOKEEPER_HOME. Variable Value will be the directory of where you installed the ZooKeeper. Taking mine for example, it would be C:\dev\tools\zookeeper-3.x.x.
  • zook env var 1

  • Now we have to edit the PATH variable. Select Path from the list and click Edit...
  • It is VERY important that you DO NOT erase the pre-existing value of the Path variable. At the very end of the variable value, add the following: %ZOOKEEPER_HOME%\bin; Also, each value needs to be separated by semicolon.
  • zook env var

  • Once that’s done, click OK and exit out of them all.

That takes care of the ZooKeeper installation part. Now we have to configure it so the instance of ZooKeeper will run properly.

2. Configuring ZooKeeper Server

If you look at the <zookeeper-install-directory> there should be a conf folder. Open that up, and then you’ll see a zoo-sample.cfg file. Copy and paste it in the same directory, it should produce a zoo-sample - Copy.cfg file. Open that with your favorite text editor (Microsoft Notepad should work as well).

Edit the file as follows:

tickTime=2000
initLimit=5
syncLimit=5
dataDir=/usr/zookeeper/data
clientPort=2181
server.1=localhost:2888:3888

NOTE: you really don’t need lines 2 (initLimit=5), 3 (syncLimit=5), and 6 (server.1=localhost:2888:3888). They’re just there for a good practice purposes, and especially for setting up a multi-server cluster, which we are not going to do here.

Save it as zoo.cfg. Also the original zoo-sample.cfg file, go ahead and delete it, as it is not needed.

Next step is to create a myid file. If you noticed earlier in the zoo.cfg file, we wrote dataDir=/usr/zookeeper/data. This is actually a directory you’re going to have to create in the C drive. Simply put, this is the directory that ZooKeeper is going to look at to identify that instance of ZooKeeper. We’re going to write 1 in that file.

So go ahead and create that usr/zookeeper/data directory, and then open up your favorite text editor.

Just type in 1, and save it as myid, set the file type as All files. This may not be insignificant, but we are going to not provide it any file extension, this is just for the convention.

myid

Don’t worry about the version-2 directory from the picture. That is automatically generated once you start the instance of ZooKeeper server.

At this point, you should be done configuring ZooKeeper. Now close out of everything, click the Start button, and open up a command prompt.

3. Test an Instance of Running ZooKeeper Server

Type in the following command: zkServer.cmd and hit enter. You should get some junk like this that don’t mean much to us.

zookeeper fire up

Now open up another command prompt in a new window. Type in the following command: zkCli.cmd and hit enter. Assuming you did everything correctly, you should get [zk: localhost:2181<CONNECTED> 0] at the very last line. See picture below:

zookeeper client

If you are getting the same result, then you setup ZooKeeper server correctly. Thanks for reading, and happy zookeeping!

[ Tutorial ] ZNode Types and How to Create, Read, Delete, and Write in ZooKeeper (Java)

Please click here to read about Create, Read, Delete, and Write znodes in ZooKeeper Client.

This is more like a continuation of my blog entry about creating, deleting, reading, and writing a znode in ZooKeeper Client. It will be mostly a few snippets of code. Although there are multiple ways, I will only present the simplest and easiest ways to create, read, delete and write znodes.

1. Creating a Znode

Java’s ZooKeeper create method takes in 4 parameters: Path [String], Data [byte array], Access Control List [ArrayList] and Mode [CreateMode]. Enclosed in the square brackets is the object type each parameter is.

As mentioned few times in my earlier blog entries, path always needs to start with the root znode ( / ). Remember, the path consists of the root znode and the name of the znode you want to create. For example, to create a znode called new_znode, you would write /new_znode for its path.

Data of a znode is stored in byte array. For the learning purposes, we will use the getBytes() method, which is a String method that converts String into byte array. Size of each znode is 1MB.

Access Control List (ACL) is stored in an ArrayList. We will use the final variable in the Ids class, which we will need to import. Furthermore, I will talk about the ACL more in detail. But for now, we will just stick with the Ids class.

Mode is the types of znodes I mentioned on my last blog entry: persistent, ephemeral, and sequential. We will be importing the CreateMode class to do this. There are four modes: Persistent (default), Persistent-Sequential, Ephemeral, and Ephemeral-Sequential. For now, we will use the default mode.

Example create method:

public void createZnode(String path, byte[] data) throws KeeperException, InterruptedException {
    zk.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}

create method throws KeeperException and InterruptedException. To anticipate the possibility of throwing either exceptions, surround the create method in a try...catch block.

Another example create method:

try {
    zk.create("/new_znode", "new znode".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} catch(InterruptedException intrEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" already exists!");
} catch(KeeperException kpEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" already exists!");
}

2. Reading a Znode

To read a znode, we call the getData method. It takes 3 parameters: Path [String], watch [boolean], stat [Stat].

Again, it takes in the path to specify which znode you want to read. Watcher is relatively a simple concept, but I will talk more about this later. Stat contains a more in-depth information about the znode, such as number of children, when it was created, etc. Like the create method, this also throws InterruptedException and KeeperException.

Example getData method:

public byte[] readZnode(String path) throws KeeperException, InterruptedException {
    return zk.getData(path, true, zk.exists(path, true));
}

Another example getData method using try...catch block:

try {
    zk.getData("/new_znode", true, zk.exists("/new_znode", true));
} catch(InterruptedException intrEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" does not exist!");
} catch(KeeperException kpEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" does not exist!");
}

As you may have noticed, getData takes in a Watcher as part of the parameter. Watcher in a nutshell is a mechanism implemented in the ZooKeeper that keeps watch of the znode you specified; it serves to notify the client whether it has been deleted, its data has changed, or if there was any changes to that znode, it will notify the client. One thing to note is that once the Watcher notified the client of a watch_me znode (for example), a new Watcher needs to be set on that same znode again, or else it will not notify the client for the second time.

3. Writing (or Re-Writing) to a Znode

We use setData for writing to a znode. This method takes in 3 parameters: Path [String] as always, data [byte Array] that will overwrite the pre-existing data, and the version [int].

We have a new parameter (but fairly self-explanatory), which is version. Every time the znode gets updated, it makes sense to update its version. Because of this, if you try to pass in the integer value that is not a current version, it will throw a BadVersionException. Here is an example:

version

I have a znode named newznode and its dataVersion is 5. It would be a major hassle to go back to the code to update its version manually every time the client tries to update its data. Instead, we utilize the getVersion method (from Stat class) and pass that as an argument as follows:

public void writeZnode(String path, byte[] data) throws KeeperException, InterruptedException {
    Stat stat = zk.exists(path, true);
    zk.setData(path, data, stat.getVersion());
}

As usual, another example of setData method using the try...catch block:

try {
    Stat stat = zk.exists("/new_znode", true);
    zk.setData("/new_znode", "new data".getBytes(), stat.getVersion());
} catch(InterruptedException intrEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" does not exist!");
} catch(KeeperException kpEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" does not exist!");
}

Now, let’s try to pass in a random integer other than its version. Same scenario (except its version is now 6).

error version

Instead of passing in the stat.getVersion() like I should be, I’ll try to pass in a non-6 value, and you should expect to see this:

exception error

4. Deleting a Znode

To delete a znode, first we use the delete method (I’m sure you could have guessed that much), and it takes in 2 parameters: Path [String] and Version [int]. Again, because I have already went over these two parameters, I will move straight into the code. Version parameter in this method is exactly the same as the version from the setData method.

public void deleteZnode(String path) throws KeeperException, InterruptedException {
    Stat stat = zk.exists(path, true);
    zk.delete(path, stat.getVersion());
}

And finally, another (and the last) example using the try...catch block:

try {
    Stat stat = zk.exists("/new_znode", true);
    zk.delete("/new_znode", stat.getVersion());
} catch(InterruptedException intrEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" does not exist!");
} catch(KeeperException kpEx) {
    // do something to prevent the program from crashing
    System.out.println("\"new_znode\" does not exist!");
}

Thanks for reading. Happy zookeeping

[ Tutorial ] ZNode Types and How to Create, Read, Delete, and Write in ZooKeeper (via zkClient)

Please click here to read about Create, Read, Delete, and Write znodes in Java.

About a month ago, I wrote a blog entry about how to connect to a ZooKeeper.  Now, I will talk about how to create, read, delete, and write the znodes, which are what I will refer to as the permission sets later on.  First way is to do it via command prompt (in Windows) as a client, and on my next blog entry, I will talk about how to do them in Java.

Each znode has its own permission sets.  They are: Create, Read, Delete, Write, and Admin (abbreviated CRDWA).  I will talk more in detail about the permission sets, how to set them, as well as the access control list (ACL) in the later blog posts.

1. Types of Znodes

Before I get into creating them, let’s briefly talk about the types of znodes: persistent, ephemeral, and sequential.

1.1. Persistent Znodes

These are the default znodes in ZooKeeper.  They will stay in the zookeeper server permanently, as long as any other clients (including the creator) leave it alone.

1.2. Ephemeral Znodes

Ephemeral znodes (also referred as session znodes) are temporary znodes.  Unlike the persistent znodes, they are destroyed as soon as the creator client logs out of the ZooKeeper server. For example, let’s say client1 created eznode1.  Once client1 logs out of the ZooKeeper server, the eznode1 gets destroyed.  

1.3. Sequential Znodes

Sequential znode is given a 10-digit number in a numerical order at the end of its name.  Let’s say client1 created a sznode1.  In the ZooKeeper server, the sznode1 will be named like this:

sznode0000000001

If client1 creates another sequential znode, it would bear the next number in a sequence.  So the next sequential znode will be called <znode name>0000000002.

2. Znode “Anatomy”

Each znode has variety of different stats, such as its path, name, data it stores, when it was created, its own permission sets, etc.  For the sake of simplicity and demonstration, I will only talk about the path, name and data.

Path of all znodes will ALWAYS start with the root, or a slash symbol.  In this example, the path of znode1 would be as follows: /znode1, and its name is znode1.  All znodes consist of data (it can also be blank).  Keep in mind that data is stored in a byte array, because this will be important to know by the time we deal with znode data in Java.

In order to do anything with a znode, you must specify its path.  If you only specify its name, it will tell you about the syntax error, so keep that in mind.

3. Creating a Znode

As mentioned earlier, znodes are persistent by default.  In a ZooKeeper client, we type in commands to perform different actions with the znode, such as create, delete, update its data, etc.

To create a znode, we need to specify its path (see above).  Now remember, a path of any znode ALWAYS starts with the root znode.  The command syntax for creating a znode is as follows:

create -<options> /<znode-name> <znode-data>

With that in mind, following are the examples for creating different types of znodes:

Persistent (Default): create /znode mydata

Ephemeral: create –e /eznode mydata

Sequential: create –s /sznode mydata

Each znode can also have a child znodes; this really depends on the permission set of that particular znode.  For instance, if a nochild znode has a RDWA permission set, where create is not allowed, then nochild znode cannot have any children znodes.  Please note that in the following syntax:

create /<parent-znode>/<child-znode> <child-znode-data>

the <parent-znode> MUST exist in order to create the <child-znode%gt;; otherwise, it will not work.

** NOTE: ephemeral znodes CANNOT contain any child znode!  Because ephemeral znodes are temporary, they will be destroyed should the creator client logs out of the ZooKeeper server, meaning all children znodes under that ephemeral znode will be destroyed automatically as well. To prevent that, ephemeral znodes cannot bear any child znode.

4. Deleting a Znode

There are 2 ways to delete a znode.  First way is to just typical deletion, and second way is recursive deletion.

delete /<znode>

We have a deleteme znode, and as you may have guessed, following command deletes the deleteme znode:

delete /deleteme

If we wanted to delete a child znode (i_am_bug in this example) instead, we just need to specify the path of that child znode, like so:

delete /i_have_bug/i_am_bug

Second way to delete a znode is recursive deletion.  This method is necessary to delete a znode with child(ren) znode(s), because using the delete command will not work.

Recursion in general is taking a big problem, and taking baby steps to solve it.  It’s also known as the “divide and conquer” approach of solving the problem.  In this case, it will start deleting znodes at the lowermost level first, one by one, then work its way up.

rmr /<znode-with-child>

I really like this command, because it works with znodes without child(ren) z(s) as well. In that case, might as well use rmr command for any other znodes, just be careful not to delete the child znode you need to keep.

5. Reading a Znode Data

Here, we use the get command to fetch the data of that particular znode.  As always, specify the path of the znode you want to get the data off of.

get /<znode-name>

This command will also return what’s also known as the stat.  Data is located on the top line.  Stat provides the detailed information of the znode, such as when it was created/re-written, version, number of children it contains, etc.

The only time get command will not work on a znode is if the read permission is not allowed in the permission set, or if the znode has ACL (Access Control List) set to digest, hosts (depends on the hosts), or IP (also depends on the IP).  I will talk more about the ACL in my later blog posts.

6. (Re) Writing a Znode Data

We use the set command to overwriting the znode data.  As always, specify the path of the znode you want to overwrite.

set /<znode-name> <new-data>

Once executed, it will return the stat of the znode, excluding the new data you have set.  Like the get command, the set command will not work if the write permission is not allowed in the permission set, or if its ACL has been configured accordingly.

By now, you should be able to execute basic commands for the znodes. In the next blog post, I will talk about how to do them in Java.

[ Tutorial ] Maven – Connect to a ZooKeeper in Java

This tutorial will cover how to connect to ZooKeeper in Java with Maven project.

(Click here to download the source code for this tutorial)

1. What is Apache Maven?

Apache Maven (or just Maven) is simply “a software project management and comprehension tool.” (from http://maven.apache.org)  In this case, Maven is designed to help you with downloading what’s called dependency – think of them as the external JAR files you need to explicitly download and include them in your build path.

1.1. Create Maven Project

Maven utilizes POM (Project Object Model); this is what makes Maven very useful.  You specify the required dependencies here, and after updating the project, it will automatically download the dependencies for you.

First step is to create a Maven project.  (How to create Maven project). Under the maven project you just created, you will see an xml file called pom.xml.

1.2. Configure Project

Image

Open that, and edit it as follows:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>zook</groupId>
    <artifactId>zook</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <name>zook</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
        </dependency>
    </dependencies>
</project>

Right click on your project > Maven > Update Project (or Alt + F5).  This usually works for me if “Force Update of Snapshots/Releases” is checked.

Image

Then click OK.

This enables you to use any classes included in that zookeeper dependency.

2. Connect to ZooKeeper

2.1. ZooKeeper Connector Class

Next step is to create a new class, let’s call it ZkConnector.

Here, you are going to import 6 following classes:

import java.io.IOException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooKeeper.States;

ZkConnector class is for your program to interact with ZooKeeper server.  We will declare two global variables here:

ZooKeeper zookeeper;
java.util.concurrent.CountDownLatch connectedSignal = new java.util.concurrent.CountDownLatch(1);

and write three different methods.  First method connects to the ZooKeeper server by passing a hosts argument.  Another method tells ZooKeeper server to shut down, and the third method gets the instance of live ZooKeeper server.

2.2. Connect method

public void connect(String host) throws IOException, InterruptedException {
    zookeeper = new ZooKeeper(host, 5000, 
                              new Watcher() {
                                  public void process(WatchedEvent event) {
                                      if (event.getState() == KeeperState.SyncConnected) {
                                          connectedSignal.countDown();
                                      }
                                  }
                              });
                              connectedSignal.await();
}

2.3. Close method

public void close() throws InterruptedException {
    zookeeper.close();
}

2.4. Getter method:

public ZooKeeper getZooKeeper() {
    if (zookeeper == null || !zookeeper.getState().equals(States.CONNECTED)) {
        throw new IllegalStateException("ZooKeeper is not connected.");
    }
    return zookeeper;
}

3. Test ZooKeeper Connection

3.1. Tester Class

Let’s test this class to see if it works.

We’re going to create another class, call it ZkConnectTest. This class will import 5 classes as follows:

import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

Many methods in the zookeeper API throw exceptions.  We need to add a throws declaration to the main method of three exceptions: IOException, InterruptedException, KeeperException.  Another way is to enclose the exception throwing statements with try... catch, but we’ll make our main method throw those exceptions.

First, let’s declare a new ZooKeeper variable, call it zk.

ZooKeeper zk;

Next, create a new instance of the ZkConnector class, let’s call it zkc.

ZkConnector zkc = new ZkConnector();

In the last 3 lines, we are going to:

  • connect to the zookeeper
  • let zk be the instance of the zookeeper connected
  • and create a new znode, just to see if it worked correctly.
zkc.connect("localhost");
zk = zkc.getZooKeeper();
zk.create("/newznode", "new znode".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

3.2. Run an Instance of ZooKeeper

Save your source code and let’s create the ZooKeeper instance.  We need to have an instance of ZooKeeper running in order for your program to work. Open up a command prompt (if you’re using windows), or a terminal (Mac or Linux users) and type in the following command:

Windows users: zkServer.cmd
Mac/Linux users:  ./zkServer.sh -start

3.3. Interact With ZooKeeper as Client

Next, we are going to connect to the zookeeper as a client.  Open up another command prompt (windows) or a terminal (Mac or Linux) and type in the following command:

Windows users: zkCli.cmd
Mac/Linux users: ./zkCli.sh -server:2181

In the client window, type in the following command: ls /

If you have not created any znodes yet, you should only get zookeeper znode.  This is implemented in the zookeeper by default, and it cannot be destroyed.  What we just did was print a list of all children znodes of the root (/) znode.

Go back to the program we wrote, and run it.

Then go back to the client window, and type in the ls / command.  If you see the newznode, then we successfully wrote a program to connect to the zookeeper. Thanks for reading, and happy zookeeping.

(Click here to download the source code for this tutorial)