zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [18/51] [partial] zookeeper git commit: ZOOKEEPER-3032: MAVEN MIGRATION - zookeeper-server
Date Fri, 19 Oct 2018 12:40:16 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
new file mode 100644
index 0000000..300143a
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java
@@ -0,0 +1,664 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.cli.CliException;
+import org.apache.zookeeper.cli.CommandNotFoundException;
+import org.apache.zookeeper.cli.MalformedCommandException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.data.Stat;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.zookeeper.cli.AddAuthCommand;
+import org.apache.zookeeper.cli.CliCommand;
+import org.apache.zookeeper.cli.CloseCommand;
+import org.apache.zookeeper.cli.CreateCommand;
+import org.apache.zookeeper.cli.DelQuotaCommand;
+import org.apache.zookeeper.cli.DeleteAllCommand;
+import org.apache.zookeeper.cli.DeleteCommand;
+import org.apache.zookeeper.cli.RemoveWatchesCommand;
+import org.apache.zookeeper.cli.GetAclCommand;
+import org.apache.zookeeper.cli.GetCommand;
+import org.apache.zookeeper.cli.GetConfigCommand;
+import org.apache.zookeeper.cli.ListQuotaCommand;
+import org.apache.zookeeper.cli.Ls2Command;
+import org.apache.zookeeper.cli.LsCommand;
+import org.apache.zookeeper.cli.ReconfigCommand;
+import org.apache.zookeeper.cli.SetAclCommand;
+import org.apache.zookeeper.cli.SetCommand;
+import org.apache.zookeeper.cli.SetQuotaCommand;
+import org.apache.zookeeper.cli.StatCommand;
+import org.apache.zookeeper.cli.SyncCommand;
+import org.apache.zookeeper.client.ZKClientConfig;
+import org.apache.zookeeper.admin.ZooKeeperAdmin;
+import org.apache.zookeeper.server.ExitCode;
+
+/**
+ * The command line client to ZooKeeper.
+ *
+ */
+@InterfaceAudience.Public
+public class ZooKeeperMain {
+    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperMain.class);
+    static final Map<String,String> commandMap = new HashMap<String,String>( );
+    static final Map<String,CliCommand> commandMapCli =
+            new HashMap<String,CliCommand>( );
+
+    protected MyCommandOptions cl = new MyCommandOptions();
+    protected HashMap<Integer,String> history = new HashMap<Integer,String>( );
+    protected int commandCount = 0;
+    protected boolean printWatches = true;
+    protected int exitCode = ExitCode.EXECUTION_FINISHED.getValue();
+
+    protected ZooKeeper zk;
+    protected String host = "";
+
+    public boolean getPrintWatches( ) {
+        return printWatches;
+    }
+
+    static {
+        commandMap.put("connect", "host:port");
+        commandMap.put("history","");
+        commandMap.put("redo","cmdno");
+        commandMap.put("printwatches", "on|off");
+        commandMap.put("quit", "");
+
+        new CloseCommand().addToMap(commandMapCli);
+        new CreateCommand().addToMap(commandMapCli);
+        new DeleteCommand().addToMap(commandMapCli);
+        new DeleteAllCommand().addToMap(commandMapCli);
+        // Depricated: rmr
+        new DeleteAllCommand("rmr").addToMap(commandMapCli);
+        new SetCommand().addToMap(commandMapCli);
+        new GetCommand().addToMap(commandMapCli);
+        new LsCommand().addToMap(commandMapCli);
+        new Ls2Command().addToMap(commandMapCli);
+        new GetAclCommand().addToMap(commandMapCli);
+        new SetAclCommand().addToMap(commandMapCli);
+        new StatCommand().addToMap(commandMapCli);
+        new SyncCommand().addToMap(commandMapCli);
+        new SetQuotaCommand().addToMap(commandMapCli);
+        new ListQuotaCommand().addToMap(commandMapCli);
+        new DelQuotaCommand().addToMap(commandMapCli);
+        new AddAuthCommand().addToMap(commandMapCli);
+        new ReconfigCommand().addToMap(commandMapCli);
+        new GetConfigCommand().addToMap(commandMapCli);
+        new RemoveWatchesCommand().addToMap(commandMapCli);
+        
+        // add all to commandMap
+        for (Entry<String, CliCommand> entry : commandMapCli.entrySet()) {
+            commandMap.put(entry.getKey(), entry.getValue().getOptionStr());
+    }
+    }
+
+    static void usage() {
+        System.err.println("ZooKeeper -server host:port cmd args");
+        List<String> cmdList = new ArrayList<String>(commandMap.keySet());
+        Collections.sort(cmdList);
+        for (String cmd : cmdList) {
+            System.err.println("\t"+cmd+ " " + commandMap.get(cmd));
+        }
+    }
+
+    private class MyWatcher implements Watcher {
+        public void process(WatchedEvent event) {
+            if (getPrintWatches()) {
+                ZooKeeperMain.printMessage("WATCHER::");
+                ZooKeeperMain.printMessage(event.toString());
+            }
+        }
+    }
+
+    /**
+     * A storage class for both command line options and shell commands.
+     *
+     */
+    static class MyCommandOptions {
+
+        private Map<String,String> options = new HashMap<String,String>();
+        private List<String> cmdArgs = null;
+        private String command = null;
+        public static final Pattern ARGS_PATTERN = Pattern.compile("\\s*([^\"\']\\S*|\"[^\"]*\"|'[^']*')\\s*");
+        public static final Pattern QUOTED_PATTERN = Pattern.compile("^([\'\"])(.*)(\\1)$");
+
+        public MyCommandOptions() {
+          options.put("server", "localhost:2181");
+          options.put("timeout", "30000");
+        }
+
+        public String getOption(String opt) {
+            return options.get(opt);
+        }
+
+        public String getCommand( ) {
+            return command;
+        }
+
+        public String getCmdArgument( int index ) {
+            return cmdArgs.get(index);
+        }
+
+        public int getNumArguments( ) {
+            return cmdArgs.size();
+        }
+
+        public String[] getArgArray() {
+            return cmdArgs.toArray(new String[0]);
+        }
+
+        /**
+         * Parses a command line that may contain one or more flags
+         * before an optional command string
+         * @param args command line arguments
+         * @return true if parsing succeeded, false otherwise.
+         */
+        public boolean parseOptions(String[] args) {
+            List<String> argList = Arrays.asList(args);
+            Iterator<String> it = argList.iterator();
+
+            while (it.hasNext()) {
+                String opt = it.next();
+                try {
+                    if (opt.equals("-server")) {
+                        options.put("server", it.next());
+                    } else if (opt.equals("-timeout")) {
+                        options.put("timeout", it.next());
+                    } else if (opt.equals("-r")) {
+                        options.put("readonly", "true");
+                    }
+                } catch (NoSuchElementException e){
+                    System.err.println("Error: no argument found for option "
+                            + opt);
+                    return false;
+                }
+
+                if (!opt.startsWith("-")) {
+                    command = opt;
+                    cmdArgs = new ArrayList<String>( );
+                    cmdArgs.add( command );
+                    while (it.hasNext()) {
+                        cmdArgs.add(it.next());
+                    }
+                    return true;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Breaks a string into command + arguments.
+         * @param cmdstring string of form "cmd arg1 arg2..etc"
+         * @return true if parsing succeeded.
+         */
+        public boolean parseCommand( String cmdstring ) {
+            Matcher matcher = ARGS_PATTERN.matcher(cmdstring);
+
+            List<String> args = new LinkedList<String>();
+            while (matcher.find()) {
+                String value = matcher.group(1);
+                if (QUOTED_PATTERN.matcher(value).matches()) {
+                    // Strip off the surrounding quotes
+                    value = value.substring(1, value.length() - 1);
+                }
+                args.add(value);
+            }
+            if (args.isEmpty()){
+                return false;
+            }
+            command = args.get(0);
+            cmdArgs = args;
+            return true;
+        }
+    }
+
+
+    /**
+     * Makes a list of possible completions, either for commands
+     * or for zk nodes if the token to complete begins with /
+     *
+     */
+
+
+    protected void addToHistory(int i,String cmd) {
+        history.put(i, cmd);
+    }
+
+    public static List<String> getCommands() {
+        List<String> cmdList = new ArrayList<String>(commandMap.keySet());
+        Collections.sort(cmdList);
+        return cmdList;
+    }
+
+    protected String getPrompt() {       
+        return "[zk: " + host + "("+zk.getState()+")" + " " + commandCount + "] ";
+    }
+
+    public static void printMessage(String msg) {
+        System.out.println("\n"+msg);
+    }
+
+    protected void connectToZK(String newHost) throws InterruptedException, IOException {
+        if (zk != null && zk.getState().isAlive()) {
+            zk.close();
+        }
+
+        host = newHost;
+        boolean readOnly = cl.getOption("readonly") != null;
+        if (cl.getOption("secure") != null) {
+            System.setProperty(ZKClientConfig.SECURE_CLIENT, "true");
+            System.out.println("Secure connection is enabled");
+        }
+        zk = new ZooKeeperAdmin(host, Integer.parseInt(cl.getOption("timeout")), new MyWatcher(), readOnly);
+    }
+    
+    public static void main(String args[]) throws CliException, IOException, InterruptedException
+    {
+        ZooKeeperMain main = new ZooKeeperMain(args);
+        main.run();
+    }
+
+    public ZooKeeperMain(String args[]) throws IOException, InterruptedException {
+        cl.parseOptions(args);
+        System.out.println("Connecting to " + cl.getOption("server"));
+        connectToZK(cl.getOption("server"));
+    }
+
+    public ZooKeeperMain(ZooKeeper zk) {
+      this.zk = zk;
+    }
+
+    void run() throws CliException, IOException, InterruptedException {
+        if (cl.getCommand() == null) {
+            System.out.println("Welcome to ZooKeeper!");
+
+            boolean jlinemissing = false;
+            // only use jline if it's in the classpath
+            try {
+                Class<?> consoleC = Class.forName("jline.console.ConsoleReader");
+                Class<?> completorC =
+                    Class.forName("org.apache.zookeeper.JLineZNodeCompleter");
+
+                System.out.println("JLine support is enabled");
+
+                Object console =
+                    consoleC.getConstructor().newInstance();
+
+                Object completor =
+                    completorC.getConstructor(ZooKeeper.class).newInstance(zk);
+                Method addCompletor = consoleC.getMethod("addCompleter",
+                        Class.forName("jline.console.completer.Completer"));
+                addCompletor.invoke(console, completor);
+
+                String line;
+                Method readLine = consoleC.getMethod("readLine", String.class);
+                while ((line = (String)readLine.invoke(console, getPrompt())) != null) {
+                    executeLine(line);
+                }
+            } catch (ClassNotFoundException e) {
+                LOG.debug("Unable to start jline", e);
+                jlinemissing = true;
+            } catch (NoSuchMethodException e) {
+                LOG.debug("Unable to start jline", e);
+                jlinemissing = true;
+            } catch (InvocationTargetException e) {
+                LOG.debug("Unable to start jline", e);
+                jlinemissing = true;
+            } catch (IllegalAccessException e) {
+                LOG.debug("Unable to start jline", e);
+                jlinemissing = true;
+            } catch (InstantiationException e) {
+                LOG.debug("Unable to start jline", e);
+                jlinemissing = true;
+            }
+
+            if (jlinemissing) {
+                System.out.println("JLine support is disabled");
+                BufferedReader br =
+                    new BufferedReader(new InputStreamReader(System.in));
+
+                String line;
+                while ((line = br.readLine()) != null) {
+                    executeLine(line);
+                }
+            }
+        } else {
+            // Command line args non-null.  Run what was passed.
+            processCmd(cl);
+        }
+        System.exit(exitCode);
+    }
+
+    public void executeLine(String line) throws CliException, InterruptedException, IOException {
+      if (!line.equals("")) {
+        cl.parseCommand(line);
+        addToHistory(commandCount,line);
+        processCmd(cl);
+        commandCount++;
+      }
+    }
+
+    /**
+     * trim the quota tree to recover unwanted tree elements
+     * in the quota's tree
+     * @param zk the zookeeper client
+     * @param path the path to start from and go up and see if their
+     * is any unwanted parent in the path.
+     * @return true if sucessful
+     * @throws KeeperException
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    private static boolean trimProcQuotas(ZooKeeper zk, String path)
+        throws KeeperException, IOException, InterruptedException
+    {
+        if (Quotas.quotaZookeeper.equals(path)) {
+            return true;
+        }
+        List<String> children = zk.getChildren(path, false);
+        if (children.size() == 0) {
+            zk.delete(path, -1);
+            String parent = path.substring(0, path.lastIndexOf('/'));
+            return trimProcQuotas(zk, parent);
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * this method deletes quota for a node.
+     * @param zk the zookeeper client
+     * @param path the path to delete quota for
+     * @param bytes true if number of bytes needs to
+     * be unset
+     * @param numNodes true if number of nodes needs
+     * to be unset
+     * @return true if quota deletion is successful
+     * @throws KeeperException
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public static boolean delQuota(ZooKeeper zk, String path,
+            boolean bytes, boolean numNodes)
+        throws KeeperException, IOException, InterruptedException
+    {
+        String parentPath = Quotas.quotaZookeeper + path;
+        String quotaPath = Quotas.quotaZookeeper + path + "/" + Quotas.limitNode;
+        if (zk.exists(quotaPath, false) == null) {
+            System.out.println("Quota does not exist for " + path);
+            return true;
+        }
+        byte[] data = null;
+        try {
+            data = zk.getData(quotaPath, false, new Stat());
+        } catch(KeeperException.NoNodeException ne) {
+            System.err.println("quota does not exist for " + path);
+            return true;
+        }
+        StatsTrack strack = new StatsTrack(new String(data));
+        if (bytes && !numNodes) {
+            strack.setBytes(-1L);
+            zk.setData(quotaPath, strack.toString().getBytes(), -1);
+        } else if (!bytes && numNodes) {
+            strack.setCount(-1);
+            zk.setData(quotaPath, strack.toString().getBytes(), -1);
+        } else if (bytes && numNodes) {
+            // delete till you can find a node with more than
+            // one child
+            List<String> children = zk.getChildren(parentPath, false);
+            /// delete the direct children first
+            for (String child: children) {
+                zk.delete(parentPath + "/" + child, -1);
+            }
+            // cut the tree till their is more than one child
+            trimProcQuotas(zk, parentPath);
+        }
+        return true;
+    }
+
+    private static void checkIfParentQuota(ZooKeeper zk, String path)
+        throws InterruptedException, KeeperException
+    {
+        final String[] splits = path.split("/");
+        String quotaPath = Quotas.quotaZookeeper;
+        for (String str: splits) {
+            if (str.length() == 0) {
+                // this should only be for the beginning of the path
+                // i.e. "/..." - split(path)[0] is empty string before first '/'
+                continue;
+            }
+            quotaPath += "/" + str;
+            List<String> children =  null;
+            try {
+                children = zk.getChildren(quotaPath, false);
+            } catch(KeeperException.NoNodeException ne) {
+                LOG.debug("child removed during quota check", ne);
+                return;
+            }
+            if (children.size() == 0) {
+                return;
+            }
+            for (String child: children) {
+                if (Quotas.limitNode.equals(child)) {
+                    throw new IllegalArgumentException(path + " has a parent "
+                            + quotaPath + " which has a quota");
+                }
+            }
+        }
+    }
+
+    /**
+     * this method creates a quota node for the path
+     * @param zk the ZooKeeper client
+     * @param path the path for which quota needs to be created
+     * @param bytes the limit of bytes on this path
+     * @param numNodes the limit of number of nodes on this path
+     * @return true if its successful and false if not.
+     */
+    public static boolean createQuota(ZooKeeper zk, String path,
+            long bytes, int numNodes)
+        throws KeeperException, IOException, InterruptedException
+    {
+        // check if the path exists. We cannot create
+        // quota for a path that already exists in zookeeper
+        // for now.
+        Stat initStat = zk.exists(path, false);
+        if (initStat == null) {
+            throw new IllegalArgumentException(path + " does not exist.");
+        }
+        // now check if their is already existing
+        // parent or child that has quota
+
+        String quotaPath = Quotas.quotaZookeeper;
+        // check for more than 2 children --
+        // if zookeeper_stats and zookeeper_qutoas
+        // are not the children then this path
+        // is an ancestor of some path that
+        // already has quota
+        String realPath = Quotas.quotaZookeeper + path;
+        try {
+            List<String> children = zk.getChildren(realPath, false);
+            for (String child: children) {
+                if (!child.startsWith("zookeeper_")) {
+                    throw new IllegalArgumentException(path + " has child " +
+                            child + " which has a quota");
+                }
+            }
+        } catch(KeeperException.NoNodeException ne) {
+            // this is fine
+        }
+
+        //check for any parent that has been quota
+        checkIfParentQuota(zk, path);
+
+        // this is valid node for quota
+        // start creating all the parents
+        if (zk.exists(quotaPath, false) == null) {
+            try {
+                zk.create(Quotas.procZookeeper, null, Ids.OPEN_ACL_UNSAFE,
+                        CreateMode.PERSISTENT);
+                zk.create(Quotas.quotaZookeeper, null, Ids.OPEN_ACL_UNSAFE,
+                        CreateMode.PERSISTENT);
+            } catch(KeeperException.NodeExistsException ne) {
+                // do nothing
+            }
+        }
+
+        // now create the direct children
+        // and the stat and quota nodes
+        String[] splits = path.split("/");
+        StringBuilder sb = new StringBuilder();
+        sb.append(quotaPath);
+        for (int i=1; i<splits.length; i++) {
+            sb.append("/" + splits[i]);
+            quotaPath = sb.toString();
+            try {
+                zk.create(quotaPath, null, Ids.OPEN_ACL_UNSAFE ,
+                        CreateMode.PERSISTENT);
+            } catch(KeeperException.NodeExistsException ne) {
+                //do nothing
+            }
+        }
+        String statPath = quotaPath + "/" + Quotas.statNode;
+        quotaPath = quotaPath + "/" + Quotas.limitNode;
+        StatsTrack strack = new StatsTrack(null);
+        strack.setBytes(bytes);
+        strack.setCount(numNodes);
+        try {
+            zk.create(quotaPath, strack.toString().getBytes(),
+                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+            StatsTrack stats = new StatsTrack(null);
+            stats.setBytes(0L);
+            stats.setCount(0);
+            zk.create(statPath, stats.toString().getBytes(),
+                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+        } catch(KeeperException.NodeExistsException ne) {
+            byte[] data = zk.getData(quotaPath, false , new Stat());
+            StatsTrack strackC = new StatsTrack(new String(data));
+            if (bytes != -1L) {
+                strackC.setBytes(bytes);
+            }
+            if (numNodes != -1) {
+                strackC.setCount(numNodes);
+            }
+            zk.setData(quotaPath, strackC.toString().getBytes(), -1);
+        }
+        return true;
+    }
+
+    protected boolean processCmd(MyCommandOptions co) throws CliException, IOException, InterruptedException {
+        boolean watch = false;
+        try {
+            watch = processZKCmd(co);
+            exitCode = ExitCode.EXECUTION_FINISHED.getValue();
+        } catch (CliException ex) {
+            exitCode = ex.getExitCode();
+            System.err.println(ex.getMessage());
+        }
+        return watch;
+    }
+
+    protected boolean processZKCmd(MyCommandOptions co) throws CliException, IOException, InterruptedException {
+        String[] args = co.getArgArray();
+        String cmd = co.getCommand();
+        if (args.length < 1) {
+            usage();
+            throw new MalformedCommandException("No command entered");
+        }
+
+        if (!commandMap.containsKey(cmd)) {
+            usage();
+            throw new CommandNotFoundException("Command not found " + cmd);
+        }
+        
+        boolean watch = false;
+        LOG.debug("Processing " + cmd);
+
+
+        if (cmd.equals("quit")) {
+            zk.close();
+            System.exit(exitCode);
+        } else if (cmd.equals("redo") && args.length >= 2) {
+            Integer i = Integer.decode(args[1]);
+            if (commandCount <= i || i < 0) { // don't allow redoing this redo
+                throw new MalformedCommandException("Command index out of range");
+            }
+            cl.parseCommand(history.get(i));
+            if (cl.getCommand().equals("redo")) {
+                throw new MalformedCommandException("No redoing redos");
+            }
+            history.put(commandCount, history.get(i));
+            processCmd(cl);
+        } else if (cmd.equals("history")) {
+            for (int i = commandCount - 10; i <= commandCount; ++i) {
+                if (i < 0) continue;
+                System.out.println(i + " - " + history.get(i));
+            }
+        } else if (cmd.equals("printwatches")) {
+            if (args.length == 1) {
+                System.out.println("printwatches is " + (printWatches ? "on" : "off"));
+            } else {
+                printWatches = args[1].equals("on");
+            }
+        } else if (cmd.equals("connect")) {
+            if (args.length >= 2) {
+                connectToZK(args[1]);
+            } else {
+                connectToZK(host);
+            }
+        }
+        
+        // Below commands all need a live connection
+        if (zk == null || !zk.getState().isAlive()) {
+            System.out.println("Not connected");
+            return false;
+        }
+        
+        // execute from commandMap
+        CliCommand cliCmd = commandMapCli.get(cmd);
+        if(cliCmd != null) {
+            cliCmd.setZk(zk);
+            watch = cliCmd.parse(args).exec();
+        } else if (!commandMap.containsKey(cmd)) {
+             usage();
+        }
+        return watch;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperTestable.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperTestable.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperTestable.java
new file mode 100644
index 0000000..873615b
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperTestable.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class ZooKeeperTestable implements Testable {
+    private static final Logger LOG = LoggerFactory
+            .getLogger(ZooKeeperTestable.class);
+
+    private final ZooKeeper zooKeeper;
+    private final ClientCnxn clientCnxn;
+
+    ZooKeeperTestable(ZooKeeper zooKeeper, ClientCnxn clientCnxn) {
+        this.zooKeeper = zooKeeper;
+        this.clientCnxn = clientCnxn;
+    }
+
+    @Override
+    public void injectSessionExpiration() {
+        LOG.info("injectSessionExpiration() called");
+
+        clientCnxn.eventThread.queueEvent(new WatchedEvent(
+                Watcher.Event.EventType.None,
+                Watcher.Event.KeeperState.Expired, null));
+        clientCnxn.eventThread.queueEventOfDeath();
+        clientCnxn.state = ZooKeeper.States.CLOSED;
+        clientCnxn.sendThread.getClientCnxnSocket().onClosing();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/admin/ZooKeeperAdmin.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/admin/ZooKeeperAdmin.java b/zookeeper-server/src/main/java/org/apache/zookeeper/admin/ZooKeeperAdmin.java
new file mode 100644
index 0000000..9911ae4
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/admin/ZooKeeperAdmin.java
@@ -0,0 +1,254 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.admin;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.AsyncCallback.DataCallback;
+import org.apache.zookeeper.client.ZKClientConfig;
+import org.apache.zookeeper.common.StringUtils;
+import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.proto.GetDataResponse;
+import org.apache.zookeeper.proto.ReconfigRequest;
+import org.apache.zookeeper.proto.ReplyHeader;
+import org.apache.zookeeper.proto.RequestHeader;
+import org.apache.zookeeper.server.DataTree;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is the main class for ZooKeeperAdmin client library.
+ * This library is used to perform cluster administration tasks,
+ * such as reconfigure cluster membership. The ZooKeeperAdmin class
+ * inherits ZooKeeper and has similar usage pattern as ZooKeeper class.
+ * Please check {@link ZooKeeper} class document for more details.
+ *
+ * @since 3.5.3
+ */
+// See ZooKeeper.java for an explanation of why we need @SuppressWarnings("try")
+@SuppressWarnings("try")
+@InterfaceAudience.Public
+public class ZooKeeperAdmin extends ZooKeeper {
+    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperAdmin.class);
+
+    /**
+     * Create a ZooKeeperAdmin object which is used to perform dynamic reconfiguration
+     * operations.
+     *
+     * @param connectString
+     *            comma separated host:port pairs, each corresponding to a zk
+     *            server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If
+     *            the optional chroot suffix is used the example would look
+     *            like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a"
+     *            where the client would be rooted at "/app/a" and all paths
+     *            would be relative to this root - ie getting/setting/etc...
+     *            "/foo/bar" would result in operations being run on
+     *            "/app/a/foo/bar" (from the server perspective).
+     * @param sessionTimeout
+     *            session timeout in milliseconds
+     * @param watcher
+     *            a watcher object which will be notified of state changes, may
+     *            also be notified for node events
+     *
+     * @throws IOException
+     *             in cases of network failure
+     * @throws IllegalArgumentException
+     *             if an invalid chroot path is specified
+     *
+     * @see ZooKeeper#ZooKeeper(String, int, Watcher)
+     *
+     */
+    public ZooKeeperAdmin(String connectString, int sessionTimeout, Watcher watcher)
+        throws IOException {
+        super(connectString, sessionTimeout, watcher);
+    }
+
+    /**
+     * Create a ZooKeeperAdmin object which is used to perform dynamic reconfiguration
+     * operations.
+     *
+     * @param connectString
+     *            comma separated host:port pairs, each corresponding to a zk
+     *            server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If
+     *            the optional chroot suffix is used the example would look
+     *            like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a"
+     *            where the client would be rooted at "/app/a" and all paths
+     *            would be relative to this root - ie getting/setting/etc...
+     *            "/foo/bar" would result in operations being run on
+     *            "/app/a/foo/bar" (from the server perspective).
+     * @param sessionTimeout
+     *            session timeout in milliseconds
+     * @param watcher
+     *            a watcher object which will be notified of state changes, may
+     *            also be notified for node events
+     * @param conf
+     *            passing this conf object gives each client the flexibility of
+     *            configuring properties differently compared to other instances
+     *
+     * @throws IOException
+     *             in cases of network failure
+     * @throws IllegalArgumentException
+     *             if an invalid chroot path is specified
+     *
+     * @see ZooKeeper#ZooKeeper(String, int, Watcher, ZKClientConfig)
+     */
+    public ZooKeeperAdmin(String connectString, int sessionTimeout, Watcher watcher,
+            ZKClientConfig conf) throws IOException {
+        super(connectString, sessionTimeout, watcher, conf);
+    }
+
+    /**
+     * Create a ZooKeeperAdmin object which is used to perform dynamic reconfiguration
+     * operations.
+     *
+     * @param connectString
+     *            comma separated host:port pairs, each corresponding to a zk
+     *            server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If
+     *            the optional chroot suffix is used the example would look
+     *            like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a"
+     *            where the client would be rooted at "/app/a" and all paths
+     *            would be relative to this root - ie getting/setting/etc...
+     *            "/foo/bar" would result in operations being run on
+     *            "/app/a/foo/bar" (from the server perspective).
+     * @param sessionTimeout
+     *            session timeout in milliseconds
+     * @param watcher
+     *            a watcher object which will be notified of state changes, may
+     *            also be notified for node events
+     * @param canBeReadOnly
+     *            whether the created client is allowed to go to
+     *            read-only mode in case of partitioning. Read-only mode
+     *            basically means that if the client can't find any majority
+     *            servers but there's partitioned server it could reach, it
+     *            connects to one in read-only mode, i.e. read requests are
+     *            allowed while write requests are not. It continues seeking for
+     *            majority in the background.
+     *
+     * @throws IOException
+     *             in cases of network failure
+     * @throws IllegalArgumentException
+     *             if an invalid chroot path is specified
+     *
+     * @see ZooKeeper#ZooKeeper(String, int, Watcher, boolean)
+     */
+    public ZooKeeperAdmin(String connectString, int sessionTimeout, Watcher watcher,
+                     boolean canBeReadOnly) throws IOException {
+        super(connectString, sessionTimeout, watcher, canBeReadOnly);
+    }
+
+    /**
+     * Reconfigure - add/remove servers. Return the new configuration.
+     * @param joiningServers
+     *                a comma separated list of servers being added (incremental reconfiguration)
+     * @param leavingServers
+     *                a comma separated list of servers being removed (incremental reconfiguration)
+     * @param newMembers
+     *                a comma separated list of new membership (non-incremental reconfiguration)
+     * @param fromConfig
+     *                version of the current configuration
+     *                (optional - causes reconfiguration to throw an exception if configuration is no longer current)
+     * @param stat the stat of /zookeeper/config znode will be copied to this
+     *             parameter if not null.
+     * @return new configuration
+     * @throws InterruptedException If the server transaction is interrupted.
+     * @throws KeeperException If the server signals an error with a non-zero error code.
+     */
+    public byte[] reconfigure(String joiningServers, String leavingServers,
+                              String newMembers, long fromConfig, Stat stat) throws KeeperException, InterruptedException {
+        RequestHeader h = new RequestHeader();
+        h.setType(ZooDefs.OpCode.reconfig);
+        ReconfigRequest request = new ReconfigRequest(joiningServers, leavingServers, newMembers, fromConfig);
+        GetDataResponse response = new GetDataResponse();
+        ReplyHeader r = cnxn.submitRequest(h, request, response, null);
+        if (r.getErr() != 0) {
+            throw KeeperException.create(KeeperException.Code.get(r.getErr()), "");
+        }
+        if (stat != null) {
+            DataTree.copyStat(response.getStat(), stat);
+        }
+        return response.getData();
+    }
+
+    /**
+     * Convenience wrapper around reconfig that takes Lists of strings instead of comma-separated servers.
+     *
+     * @see #reconfigure
+     *
+     */
+    public byte[] reconfigure(List<String> joiningServers, List<String> leavingServers,
+                              List<String> newMembers, long fromConfig,
+                              Stat stat) throws KeeperException, InterruptedException {
+        return reconfigure(StringUtils.joinStrings(joiningServers, ","),
+                        StringUtils.joinStrings(leavingServers, ","),
+                        StringUtils.joinStrings(newMembers, ","),
+                        fromConfig, stat);
+    }
+
+    /**
+     * The Asynchronous version of reconfig.
+     *
+     * @see #reconfigure
+     *
+     **/
+    public void reconfigure(String joiningServers, String leavingServers,
+                            String newMembers, long fromConfig, DataCallback cb, Object ctx) {
+        RequestHeader h = new RequestHeader();
+        h.setType(ZooDefs.OpCode.reconfig);
+        ReconfigRequest request = new ReconfigRequest(joiningServers, leavingServers, newMembers, fromConfig);
+        GetDataResponse response = new GetDataResponse();
+        cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
+               ZooDefs.CONFIG_NODE, ZooDefs.CONFIG_NODE, ctx, null);
+    }
+
+    /**
+     * Convenience wrapper around asynchronous reconfig that takes Lists of strings instead of comma-separated servers.
+     *
+     * @see #reconfigure
+     *
+     */
+    public void reconfigure(List<String> joiningServers,
+                            List<String> leavingServers, List<String> newMembers, long fromConfig,
+                            DataCallback cb, Object ctx) {
+        reconfigure(StringUtils.joinStrings(joiningServers, ","),
+                 StringUtils.joinStrings(leavingServers, ","),
+                 StringUtils.joinStrings(newMembers, ","),
+                 fromConfig, cb, ctx);
+    }
+
+    /**
+     * String representation of this ZooKeeperAdmin client. Suitable for things
+     * like logging.
+     *
+     * Do NOT count on the format of this string, it may change without
+     * warning.
+     *
+     * @since 3.5.3
+     */
+    @Override
+    public String toString() {
+        return super.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AclParser.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AclParser.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AclParser.java
new file mode 100644
index 0000000..5aa03c1
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AclParser.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+
+/**
+ * a parser for ACL strings
+ */
+public class AclParser {
+
+    /**
+     * parse string into list of ACL
+     * @param aclString
+     * @return 
+     */
+    public static List<ACL> parse(String aclString) {
+        List<ACL> acl;
+        String acls[] = aclString.split(",");
+        acl = new ArrayList<ACL>();
+        for (String a : acls) {
+            int firstColon = a.indexOf(':');
+            int lastColon = a.lastIndexOf(':');
+            if (firstColon == -1 || lastColon == -1 || firstColon == lastColon) {
+                System.err.println(a + " does not have the form scheme:id:perm");
+                continue;
+            }
+            ACL newAcl = new ACL();
+            newAcl.setId(new Id(a.substring(0, firstColon), a.substring(
+                    firstColon + 1, lastColon)));
+            newAcl.setPerms(getPermFromString(a.substring(lastColon + 1)));
+            acl.add(newAcl);
+        }
+        return acl;
+    }
+
+    static private int getPermFromString(String permString) {
+        int perm = 0;
+        for (int i = 0; i < permString.length(); i++) {
+            switch (permString.charAt(i)) {
+                case 'r':
+                    perm |= ZooDefs.Perms.READ;
+                    break;
+                case 'w':
+                    perm |= ZooDefs.Perms.WRITE;
+                    break;
+                case 'c':
+                    perm |= ZooDefs.Perms.CREATE;
+                    break;
+                case 'd':
+                    perm |= ZooDefs.Perms.DELETE;
+                    break;
+                case 'a':
+                    perm |= ZooDefs.Perms.ADMIN;
+                    break;
+                default:
+                    System.err.println("Unknown perm type: " + permString.charAt(i));
+            }
+        }
+        return perm;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AddAuthCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AddAuthCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AddAuthCommand.java
new file mode 100644
index 0000000..e2a333a
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/AddAuthCommand.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import java.io.IOException;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+import org.apache.commons.cli.PosixParser;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * addAuth command for cli
+ */
+public class AddAuthCommand extends CliCommand {
+
+    private static Options options = new Options();
+    private String[] args;
+
+    public AddAuthCommand() {
+        super("addauth", "scheme auth");
+    }
+
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        Parser parser = new PosixParser();
+        CommandLine cl;
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+
+        args = cl.getArgs();
+        if (args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+
+        return this;
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        byte[] b = null;
+        if (args.length >= 3) {
+            b = args[2].getBytes();
+        }
+
+        zk.addAuthInfo(args[1], b);
+
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliCommand.java
new file mode 100644
index 0000000..41e3d85
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliCommand.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import java.io.PrintStream;
+import java.util.Map;
+import org.apache.zookeeper.ZooKeeper;
+
+/**
+ * base class for all CLI commands
+ */
+abstract public class CliCommand {
+    protected ZooKeeper zk;
+    protected PrintStream out;
+    protected PrintStream err;
+    private String cmdStr;
+    private String optionStr;
+
+    /**
+     * a CLI command with command string and options.
+     * Using System.out and System.err for printing
+     * @param cmdStr the string used to call this command
+     * @param optionStr the string used to call this command 
+     */
+    public CliCommand(String cmdStr, String optionStr) {
+        this.out = System.out;
+        this.err = System.err;
+        this.cmdStr = cmdStr;
+        this.optionStr = optionStr;
+    }
+
+    /**
+     * Set out printStream (useable for testing)
+     * @param out 
+     */
+    public void setOut(PrintStream out) {
+        this.out = out;
+    }
+
+    /**
+     * Set err printStream (useable for testing)
+     * @param err 
+     */
+    public void setErr(PrintStream err) {
+        this.err = err;
+    }
+
+    /**
+     * set the zookeper instance
+     * @param zk the ZooKeeper instance.
+     */
+    public void setZk(ZooKeeper zk) {
+        this.zk = zk;
+    }
+
+    /**
+     * get the string used to call this command
+     * @return 
+     */
+    public String getCmdStr() {
+        return cmdStr;
+    }
+
+    /**
+     * get the option string
+     * @return 
+     */
+    public String getOptionStr() {
+        return optionStr;
+    }
+
+    /**
+     * get a usage string, contains the command and the options
+     * @return 
+     */
+    public String getUsageStr() {
+        return cmdStr + " " + optionStr;
+    }
+
+    /**
+     * add this command to a map. Use the command string as key.
+     * @param cmdMap 
+     */
+    public void addToMap(Map<String, CliCommand> cmdMap) {
+        cmdMap.put(cmdStr, this);
+    }
+    
+    /**
+     * parse the command arguments
+     * @param cmdArgs
+     * @return this CliCommand
+     * @throws CliParseException
+     */
+    abstract public CliCommand parse(String cmdArgs[]) throws CliParseException;
+    
+    /**
+     * 
+     * @return
+     * @throws CliException
+     */
+    abstract public boolean exec() throws CliException;
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliException.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliException.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliException.java
new file mode 100644
index 0000000..6e9c6d6
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliException.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+@SuppressWarnings("serial")
+public class CliException extends Exception {
+
+    protected int exitCode;
+
+    protected static final int DEFAULT_EXCEPTION_EXIT_CODE = 1;
+
+    public CliException(String message) {
+        this(message, DEFAULT_EXCEPTION_EXIT_CODE);
+    }
+
+    public CliException(String message, int exitCode) {
+        super(message);
+        this.exitCode = exitCode;
+    }
+
+    public CliException(Throwable cause) {
+        this(cause, DEFAULT_EXCEPTION_EXIT_CODE);
+    }
+
+    public CliException(Throwable cause, int exitCode) {
+        super(cause);
+        this.exitCode = exitCode;
+    }
+
+    public CliException(String message, Throwable cause) {
+        this(message, cause, DEFAULT_EXCEPTION_EXIT_CODE);
+    }
+
+    public CliException(String message, Throwable cause, int exitCode) {
+        super(message, cause);
+        this.exitCode = exitCode;
+    }
+
+    public int getExitCode() {
+        return exitCode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliParseException.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliParseException.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliParseException.java
new file mode 100644
index 0000000..a6326dc
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliParseException.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import org.apache.commons.cli.ParseException;
+
+@SuppressWarnings("serial")
+public class CliParseException extends CliException {
+    public CliParseException(ParseException parseException) {
+        super(parseException);
+    }
+
+    public CliParseException(String message) {
+        super(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliWrapperException.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliWrapperException.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliWrapperException.java
new file mode 100644
index 0000000..c0fafda
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CliWrapperException.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import org.apache.zookeeper.KeeperException;
+
+@SuppressWarnings("serial")
+public class CliWrapperException extends CliException {
+    public CliWrapperException(Throwable cause) {
+        super(getMessage(cause), cause);
+    }
+    
+    private static String getMessage(Throwable cause) {
+        if (cause instanceof  KeeperException) {
+            KeeperException keeperException = (KeeperException) cause;
+            if (keeperException instanceof KeeperException.NoNodeException) {
+                return "Node does not exist: " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.NoChildrenForEphemeralsException) {
+                return "Ephemerals cannot have children: " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.NodeExistsException) {
+                return "Node already exists: " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.NotEmptyException) {
+                return "Node not empty: " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.NotReadOnlyException) {
+                return "Not a read-only call: " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.InvalidACLException) {
+                return "Acl is not valid : " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.NoAuthException) {
+                return "Authentication is not valid : " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.BadArgumentsException) {
+                return "Arguments are not valid : " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.BadVersionException) {
+                return "version No is not valid : " + keeperException.getPath();
+            } else if (keeperException instanceof KeeperException.ReconfigInProgress) {
+                return "Another reconfiguration is in progress -- concurrent " +
+                        "reconfigs not supported (yet)";
+            } else if (keeperException instanceof KeeperException.NewConfigNoQuorum) {
+                return "No quorum of new config is connected and " +
+                        "up-to-date with the leader of last commmitted config - try invoking reconfiguration after " +
+                        "new servers are connected and synced";
+            }
+        }
+        return cause.getMessage();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CloseCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CloseCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CloseCommand.java
new file mode 100644
index 0000000..d1c83d9
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CloseCommand.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+/**
+ * close command for cli
+ */
+public class CloseCommand extends CliCommand {
+
+    public CloseCommand() {
+        super("close", "");
+    }
+    
+    
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        return this;
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        try {
+            zk.close();
+        } catch (Exception ex) {
+            throw new CliWrapperException(ex);
+        }
+        
+        return false;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CommandNotFoundException.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CommandNotFoundException.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CommandNotFoundException.java
new file mode 100644
index 0000000..7090ef0
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CommandNotFoundException.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+@SuppressWarnings("serial")
+public class CommandNotFoundException extends CliException {
+
+    public CommandNotFoundException(String command) {
+        super("Command not found: " + command, 127);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CreateCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CreateCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CreateCommand.java
new file mode 100644
index 0000000..093be47
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/CreateCommand.java
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import java.util.List;
+import org.apache.commons.cli.*;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import org.apache.zookeeper.server.EphemeralType;
+
+/**
+ * create command for cli
+ */
+public class CreateCommand extends CliCommand {
+
+    private static Options options = new Options();
+    private String[] args;
+    private CommandLine cl;
+
+    static {
+        options.addOption(new Option("e", false, "ephemeral"));
+        options.addOption(new Option("s", false, "sequential"));
+        options.addOption(new Option("c", false, "container"));
+        options.addOption(new Option("t", true, "ttl"));
+    }
+
+    public CreateCommand() {
+        super("create", "[-s] [-e] [-c] [-t ttl] path [data] [acl]");
+    }
+
+
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        Parser parser = new PosixParser();
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+        args = cl.getArgs();
+        if(args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+        return this;
+    }
+
+
+    @Override
+    public boolean exec() throws CliException {
+        boolean hasE = cl.hasOption("e");
+        boolean hasS = cl.hasOption("s");
+        boolean hasC = cl.hasOption("c");
+        boolean hasT = cl.hasOption("t");
+        if (hasC && (hasE || hasS)) {
+            throw new MalformedCommandException("-c cannot be combined with -s or -e. Containers cannot be ephemeral or sequential.");
+        }
+        long ttl;
+        try {
+            ttl = hasT ? Long.parseLong(cl.getOptionValue("t")) : 0;
+        } catch (NumberFormatException e) {
+            throw new MalformedCommandException("-t argument must be a long value");
+        }
+
+        if (hasT && hasE) {
+            throw new MalformedCommandException("TTLs cannot be used with Ephemeral znodes");
+        }
+        if (hasT && hasC) {
+            throw new MalformedCommandException("TTLs cannot be used with Container znodes");
+        }
+
+        CreateMode flags;
+        if(hasE && hasS) {
+            flags = CreateMode.EPHEMERAL_SEQUENTIAL;
+        } else if (hasE) {
+            flags = CreateMode.EPHEMERAL;
+        } else if (hasS) {
+            flags = hasT ? CreateMode.PERSISTENT_SEQUENTIAL_WITH_TTL : CreateMode.PERSISTENT_SEQUENTIAL;
+        } else if (hasC) {
+            flags = CreateMode.CONTAINER;
+        } else {
+            flags = hasT ? CreateMode.PERSISTENT_WITH_TTL : CreateMode.PERSISTENT;
+        }
+        if (hasT) {
+            try {
+                EphemeralType.TTL.toEphemeralOwner(ttl);
+            } catch (IllegalArgumentException e) {
+                throw new MalformedCommandException(e.getMessage());
+            }
+        }
+
+        String path = args[1];
+        byte[] data = null;
+        if (args.length > 2) {
+            data = args[2].getBytes();
+        }
+        List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;
+        if (args.length > 3) {
+            acl = AclParser.parse(args[3]);
+        }
+        try {
+            String newPath = hasT ? zk.create(path, data, acl, flags, new Stat(), ttl) : zk.create(path, data, acl, flags);
+            err.println("Created " + newPath);
+        } catch(IllegalArgumentException ex) {
+            throw new MalformedPathException(ex.getMessage());
+        } catch(KeeperException.EphemeralOnLocalSessionException e) {
+            err.println("Unable to create ephemeral node on a local session");
+            throw new CliWrapperException(e);
+        } catch (KeeperException.InvalidACLException ex) {
+            err.println(ex.getMessage());
+            throw new CliWrapperException(ex);
+        } catch (KeeperException|InterruptedException ex) {
+            throw new CliWrapperException(ex);
+        }
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DelQuotaCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DelQuotaCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DelQuotaCommand.java
new file mode 100644
index 0000000..c5ed403
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DelQuotaCommand.java
@@ -0,0 +1,161 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import java.io.IOException;
+import java.util.List;
+import org.apache.commons.cli.*;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.Quotas;
+import org.apache.zookeeper.StatsTrack;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+
+/**
+ * delQuota command for cli
+ */
+public class DelQuotaCommand extends CliCommand {
+
+    private Options options = new Options();
+    private String[] args;
+    private CommandLine cl;
+
+    public DelQuotaCommand() {
+        super("delquota", "[-n|-b] path");
+
+        OptionGroup og1 = new OptionGroup();
+        og1.addOption(new Option("b", false, "bytes quota"));
+        og1.addOption(new Option("n", false, "num quota"));
+        options.addOptionGroup(og1);
+    }
+
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        Parser parser = new PosixParser();
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+        args = cl.getArgs();
+        if (args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+
+        return this;
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        //if neither option -n or -b is specified, we delete
+        // the quota node for this node.
+        String path = args[1];
+        try {
+            if (cl.hasOption("b")) {
+                delQuota(zk, path, true, false);
+            } else if (cl.hasOption("n")) {
+                delQuota(zk, path, false, true);
+            } else if (args.length == 2) {
+                // we dont have an option specified.
+                // just delete whole quota node
+                delQuota(zk, path, true, true);
+            }
+        } catch (KeeperException|InterruptedException|IOException ex) {
+            throw new CliWrapperException(ex);
+        }
+        return false;
+    }
+
+    /**
+     * this method deletes quota for a node.
+     *
+     * @param zk the zookeeper client
+     * @param path the path to delete quota for
+     * @param bytes true if number of bytes needs to be unset
+     * @param numNodes true if number of nodes needs to be unset
+     * @return true if quota deletion is successful
+     * @throws KeeperException
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public static boolean delQuota(ZooKeeper zk, String path,
+            boolean bytes, boolean numNodes)
+            throws KeeperException, IOException, InterruptedException, MalformedPathException {
+        String parentPath = Quotas.quotaZookeeper + path;
+        String quotaPath = Quotas.quotaZookeeper + path + "/" + 
+                Quotas.limitNode;
+        if (zk.exists(quotaPath, false) == null) {
+            System.out.println("Quota does not exist for " + path);
+            return true;
+        }
+        byte[] data = null;
+        try {
+            data = zk.getData(quotaPath, false, new Stat());
+        } catch (IllegalArgumentException ex) {
+            throw new MalformedPathException(ex.getMessage());
+        } catch (KeeperException.NoNodeException ne) {
+            System.err.println("quota does not exist for " + path);
+            return true;
+        }
+        StatsTrack strack = new StatsTrack(new String(data));
+        if (bytes && !numNodes) {
+            strack.setBytes(-1L);
+            zk.setData(quotaPath, strack.toString().getBytes(), -1);
+        } else if (!bytes && numNodes) {
+            strack.setCount(-1);
+            zk.setData(quotaPath, strack.toString().getBytes(), -1);
+        } else if (bytes && numNodes) {
+            // delete till you can find a node with more than
+            // one child
+            List<String> children = zk.getChildren(parentPath, false);
+            /// delete the direct children first
+            for (String child : children) {
+                zk.delete(parentPath + "/" + child, -1);
+            }
+            // cut the tree till their is more than one child
+            trimProcQuotas(zk, parentPath);
+        }
+        return true;
+    }
+
+    /**
+     * trim the quota tree to recover unwanted tree elements in the quota's tree
+     *
+     * @param zk the zookeeper client
+     * @param path the path to start from and go up and see if their is any
+     * unwanted parent in the path.
+     * @return true if sucessful
+     * @throws KeeperException
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    private static boolean trimProcQuotas(ZooKeeper zk, String path)
+            throws KeeperException, IOException, InterruptedException {
+        if (Quotas.quotaZookeeper.equals(path)) {
+            return true;
+        }
+        List<String> children = zk.getChildren(path, false);
+        if (children.size() == 0) {
+            zk.delete(path, -1);
+            String parent = path.substring(0, path.lastIndexOf('/'));
+            return trimProcQuotas(zk, parent);
+        } else {
+            return true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteAllCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteAllCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteAllCommand.java
new file mode 100644
index 0000000..a3f7853
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteAllCommand.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+import org.apache.commons.cli.PosixParser;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZKUtil;
+
+/**
+ * deleteAll command for cli
+ */
+public class DeleteAllCommand extends CliCommand {
+
+    private static Options options = new Options();
+    private String[] args;
+
+    public DeleteAllCommand() {
+        this("deleteall");
+    }
+
+    public DeleteAllCommand(String cmdStr) {
+        super(cmdStr, "path");
+    }
+    
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        Parser parser = new PosixParser();
+        CommandLine cl;
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+        args = cl.getArgs();
+        if (args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+
+        return this;
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        printDeprecatedWarning();
+        
+        String path = args[1];
+        try {
+            ZKUtil.deleteRecursive(zk, path);
+        } catch (IllegalArgumentException ex) {
+            throw new MalformedPathException(ex.getMessage());
+        } catch (KeeperException|InterruptedException ex) {
+            throw new CliWrapperException(ex);
+        }
+        return false;
+    }
+    
+    private void printDeprecatedWarning() {
+        if("rmr".equals(args[0])) {
+            err.println("The command 'rmr' has been deprecated. " +
+                  "Please use 'deleteall' instead.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteCommand.java
new file mode 100644
index 0000000..d3c67b6
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/DeleteCommand.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import org.apache.commons.cli.*;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * delete command for cli
+ */
+public class DeleteCommand extends CliCommand {
+
+    private static Options options = new Options();
+    private String[] args;
+    private CommandLine cl;
+
+    {
+        options.addOption("v", true, "version");
+    }
+
+    public DeleteCommand() {
+        super("delete", "[-v version] path");
+    }
+
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        Parser parser = new PosixParser();
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+        args = cl.getArgs();
+        if (args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+        
+        retainCompatibility(cmdArgs);
+
+        return this;
+    }
+
+    private void retainCompatibility(String[] cmdArgs) throws CliParseException {
+        if (args.length > 2) {
+            err.println("'delete path [version]' has been deprecated. "
+                    + "Please use 'delete [-v version] path' instead.");
+            Parser parser = new PosixParser();
+            try {
+                cl = parser.parse(options, cmdArgs);
+            } catch (ParseException ex) {
+                throw new CliParseException(ex);
+            }
+            args = cl.getArgs();
+        }
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        String path = args[1];
+        int version;
+        if (cl.hasOption("v")) {
+            version = Integer.parseInt(cl.getOptionValue("v"));
+        } else {
+            version = -1;
+        }
+        
+        try {
+            zk.delete(path, version);
+        } catch (IllegalArgumentException ex) {
+            throw new MalformedPathException(ex.getMessage());
+        } catch(KeeperException|InterruptedException ex) {
+            throw new CliWrapperException(ex);
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetAclCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetAclCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetAclCommand.java
new file mode 100644
index 0000000..b5feb60
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetAclCommand.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.zookeeper.cli;
+
+import java.util.List;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+import org.apache.commons.cli.PosixParser;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+
+/**
+ * getAcl command for cli
+ */
+public class GetAclCommand extends CliCommand {
+
+    private static Options options = new Options();
+    private String args[];
+    private CommandLine cl;
+
+    {
+        options.addOption("s", false, "stats");
+    }
+
+    public GetAclCommand() {
+        super("getAcl", "[-s] path");
+    }
+
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+        Parser parser = new PosixParser();
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+        args = cl.getArgs();
+        if (args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+
+        return this;
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        String path = args[1];
+        Stat stat = new Stat();
+        List<ACL> acl;
+        try {
+           acl = zk.getACL(path, stat);
+        } catch (IllegalArgumentException ex) {
+            throw new MalformedPathException(ex.getMessage());
+        } catch (KeeperException|InterruptedException ex) {
+            throw new CliWrapperException(ex);
+        }
+
+        for (ACL a : acl) {
+            out.println(a.getId() + ": "
+                        + getPermString(a.getPerms()));
+        }
+
+        if (cl.hasOption("s")) {
+            new StatPrinter(out).print(stat);
+        }
+        return false;
+    }
+
+    private static String getPermString(int perms) {
+        StringBuilder p = new StringBuilder();
+        if ((perms & ZooDefs.Perms.CREATE) != 0) {
+            p.append('c');
+        }
+        if ((perms & ZooDefs.Perms.DELETE) != 0) {
+            p.append('d');
+        }
+        if ((perms & ZooDefs.Perms.READ) != 0) {
+            p.append('r');
+        }
+        if ((perms & ZooDefs.Perms.WRITE) != 0) {
+            p.append('w');
+        }
+        if ((perms & ZooDefs.Perms.ADMIN) != 0) {
+            p.append('a');
+        }
+        return p.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/cb9f303b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetCommand.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetCommand.java
new file mode 100644
index 0000000..6e58a5e
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/GetCommand.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zookeeper.cli;
+
+import org.apache.commons.cli.*;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.data.Stat;
+
+/**
+ * get command for cli
+ */
+public class GetCommand extends CliCommand {
+
+    private static Options options = new Options();
+    private String args[];
+    private CommandLine cl;
+
+    {
+        options.addOption("s", false, "stats");
+        options.addOption("w", false, "watch");
+    }
+
+    public GetCommand() {
+        super("get", "[-s] [-w] path");
+    }
+
+    @Override
+    public CliCommand parse(String[] cmdArgs) throws CliParseException {
+
+        Parser parser = new PosixParser();
+        try {
+            cl = parser.parse(options, cmdArgs);
+        } catch (ParseException ex) {
+            throw new CliParseException(ex);
+        }
+        args = cl.getArgs();
+        if (args.length < 2) {
+            throw new CliParseException(getUsageStr());
+        }
+
+        retainCompatibility(cmdArgs);
+
+        return this;
+    }
+
+    private void retainCompatibility(String[] cmdArgs) throws CliParseException {
+        // get path [watch]
+        if (args.length > 2) {
+            // rewrite to option
+            cmdArgs[2] = "-w";
+            err.println("'get path [watch]' has been deprecated. "
+                    + "Please use 'get [-s] [-w] path' instead.");
+            Parser parser = new PosixParser();
+            try {
+                cl = parser.parse(options, cmdArgs);
+            } catch (ParseException ex) {
+                throw new CliParseException(ex);
+            }
+            args = cl.getArgs();
+        }
+    }
+
+    @Override
+    public boolean exec() throws CliException {
+        boolean watch = cl.hasOption("w");
+        String path = args[1];
+        Stat stat = new Stat();
+        byte data[];
+        try {
+            data = zk.getData(path, watch, stat);
+        } catch (IllegalArgumentException ex) {
+            throw new MalformedPathException(ex.getMessage());
+        } catch (KeeperException|InterruptedException ex) {
+            throw new CliException(ex);
+        }
+        data = (data == null) ? "null".getBytes() : data;
+        out.println(new String(data));
+        if (cl.hasOption("s")) {
+            new StatPrinter(out).print(stat);
+        }
+        return watch;
+    }
+}


Mime
View raw message