zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [16/36] zookeeper git commit: ZOOKEEPER-3032: MAVEN MIGRATION - branch-3.4 - zookeeper-server
Date Wed, 24 Oct 2018 09:32:32 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/SaslClientCallbackHandler.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/SaslClientCallbackHandler.java b/zookeeper-server/src/main/java/org/apache/zookeeper/SaslClientCallbackHandler.java
new file mode 100644
index 0000000..d6f5549
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/SaslClientCallbackHandler.java
@@ -0,0 +1,104 @@
+/**
+ * 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 javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.RealmCallback;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is used by the SASL mechanisms to get further information to complete
+ * the authentication. For example, a SASL mechanism might use this callback
+ * handler to do verification operation. The CallbackHandler interface here
+ * refers to javax.security.auth.callback.CallbackHandler. It should not be
+ * confused with ZooKeeper packet callbacks like
+ * org.apache.zookeeper.server.auth.SaslServerCallbackHandler.
+ */
+public class SaslClientCallbackHandler implements CallbackHandler {
+    private String password = null;
+    private static final Logger LOG = LoggerFactory.getLogger(SaslClientCallbackHandler.class);
+    private final String entity;
+    public SaslClientCallbackHandler(String password, String client) {
+        this.password = password;
+        this.entity = client;
+    }
+
+    public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
+        for (Callback callback : callbacks) {
+            if (callback instanceof NameCallback) {
+                NameCallback nc = (NameCallback) callback;
+                nc.setName(nc.getDefaultName());
+            }
+            else {
+                if (callback instanceof PasswordCallback) {
+                    PasswordCallback pc = (PasswordCallback)callback;
+                    if (password != null) {
+                        pc.setPassword(this.password.toCharArray());
+                    } else {
+                        LOG.warn("Could not login: the {} is being asked for a password, but the ZooKeeper {}" +
+                          " code does not currently support obtaining a password from the user." +
+                          " Make sure that the {} is configured to use a ticket cache (using" +
+                          " the JAAS configuration setting 'useTicketCache=true)' and restart the {}. If" +
+                          " you still get this message after that, the TGT in the ticket cache has expired and must" +
+                          " be manually refreshed. To do so, first determine if you are using a password or a" +
+                          " keytab. If the former, run kinit in a Unix shell in the environment of the user who" +
+                          " is running this Zookeeper {} using the command" +
+                          " 'kinit <princ>' (where <princ> is the name of the {}'s Kerberos principal)." +
+                          " If the latter, do" +
+                          " 'kinit -k -t <keytab> <princ>' (where <princ> is the name of the Kerberos principal, and" +
+                          " <keytab> is the location of the keytab file). After manually refreshing your cache," +
+                          " restart this {}. If you continue to see this message after manually refreshing" +
+                          " your cache, ensure that your KDC host's clock is in sync with this host's clock.",
+                          new Object[]{entity, entity, entity, entity, entity, entity, entity});
+                    }
+                }
+                else {
+                    if (callback instanceof RealmCallback) {
+                        RealmCallback rc = (RealmCallback) callback;
+                        rc.setText(rc.getDefaultText());
+                    }
+                    else {
+                        if (callback instanceof AuthorizeCallback) {
+                            AuthorizeCallback ac = (AuthorizeCallback) callback;
+                            String authid = ac.getAuthenticationID();
+                            String authzid = ac.getAuthorizationID();
+                            if (authid.equals(authzid)) {
+                                ac.setAuthorized(true);
+                            } else {
+                                ac.setAuthorized(false);
+                            }
+                            if (ac.isAuthorized()) {
+                                ac.setAuthorizedID(authzid);
+                            }
+                        }
+                        else {
+                            throw new UnsupportedCallbackException(callback, "Unrecognized SASL " + entity + "Callback");
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/ServerAdminClient.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ServerAdminClient.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ServerAdminClient.java
new file mode 100644
index 0000000..9464f1c
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ServerAdminClient.java
@@ -0,0 +1,316 @@
+/**
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.util.StringTokenizer;
+
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.zookeeper.server.ZooTrace;
+
+@InterfaceAudience.Public
+public class ServerAdminClient {
+    private static final Logger LOG = LoggerFactory.getLogger(ServerAdminClient.class);
+
+    private static long getMask(String mask) {
+        long retv = 0;
+        if (mask.equalsIgnoreCase("CLIENT_REQUEST_TRACE_MASK")) {
+            retv = ZooTrace.CLIENT_REQUEST_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("CLIENT_DATA_PACKET_TRACE_MASK")) {
+            retv = ZooTrace.CLIENT_DATA_PACKET_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("CLIENT_PING_TRACE_MASK")) {
+            retv = ZooTrace.CLIENT_PING_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("SERVER_PACKET_TRACE_MASK")) {
+            retv = ZooTrace.SERVER_PACKET_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("SESSION_TRACE_MASK")) {
+            retv = ZooTrace.SESSION_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("EVENT_DELIVERY_TRACE_MASK")) {
+            retv = ZooTrace.EVENT_DELIVERY_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("SERVER_PING_TRACE_MASK")) {
+            retv = ZooTrace.SERVER_PING_TRACE_MASK;
+        } else if (mask.equalsIgnoreCase("WARNING_TRACE_MASK")) {
+            retv = ZooTrace.WARNING_TRACE_MASK;
+        }
+        return retv;
+    }
+
+    private static long getMasks(String masks) {
+        long retv = 0;
+        StringTokenizer st = new StringTokenizer(masks, "|");
+        while (st.hasMoreTokens()) {
+            String mask = st.nextToken().trim();
+            retv = retv | getMask(mask);
+        }
+        return retv;
+    }
+
+    public static void ruok(String host, int port) {
+        Socket s = null;
+        try {
+            byte[] reqBytes = new byte[4];
+            ByteBuffer req = ByteBuffer.wrap(reqBytes);
+            req.putInt(ByteBuffer.wrap("ruok".getBytes()).getInt());
+            s = new Socket();
+            s.setSoLinger(false, 10);
+            s.setSoTimeout(20000);
+            s.connect(new InetSocketAddress(host, port));
+
+            InputStream is = s.getInputStream();
+            OutputStream os = s.getOutputStream();
+
+            os.write(reqBytes);
+
+            byte[] resBytes = new byte[4];
+
+            int rc = is.read(resBytes);
+            String retv = new String(resBytes);
+            System.out.println("rc=" + rc + " retv=" + retv);
+        } catch (IOException e) {
+            LOG.warn("Unexpected exception", e);
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    LOG.warn("Unexpected exception", e);
+                }
+            }
+        }
+    }
+
+    public static void dump(String host, int port) {
+        Socket s = null;
+        try {
+            byte[] reqBytes = new byte[4];
+            ByteBuffer req = ByteBuffer.wrap(reqBytes);
+            req.putInt(ByteBuffer.wrap("dump".getBytes()).getInt());
+            s = new Socket();
+            s.setSoLinger(false, 10);
+            s.setSoTimeout(20000);
+            s.connect(new InetSocketAddress(host, port));
+
+            InputStream is = s.getInputStream();
+            OutputStream os = s.getOutputStream();
+
+            os.write(reqBytes);
+
+            byte[] resBytes = new byte[1024];
+
+            int rc = is.read(resBytes);
+            String retv = new String(resBytes);
+            System.out.println("rc=" + rc + " retv=" + retv);
+        } catch (IOException e) {
+            LOG.warn("Unexpected exception", e);
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    LOG.warn("Unexpected exception", e);
+                }
+            }
+        }
+    }
+
+    public static void stat(String host, int port) {
+        Socket s = null;
+        try {
+            byte[] reqBytes = new byte[4];
+            ByteBuffer req = ByteBuffer.wrap(reqBytes);
+            req.putInt(ByteBuffer.wrap("stat".getBytes()).getInt());
+            s = new Socket();
+            s.setSoLinger(false, 10);
+            s.setSoTimeout(20000);
+            s.connect(new InetSocketAddress(host, port));
+
+            InputStream is = s.getInputStream();
+            OutputStream os = s.getOutputStream();
+
+            os.write(reqBytes);
+
+            byte[] resBytes = new byte[1024];
+
+            int rc = is.read(resBytes);
+            String retv = new String(resBytes);
+            System.out.println("rc=" + rc + " retv=" + retv);
+        } catch (IOException e) {
+            LOG.warn("Unexpected exception", e);
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    LOG.warn("Unexpected exception", e);
+                }
+            }
+        }
+    }
+
+    public static void kill(String host, int port) {
+        Socket s = null;
+        try {
+            byte[] reqBytes = new byte[4];
+            ByteBuffer req = ByteBuffer.wrap(reqBytes);
+            req.putInt(ByteBuffer.wrap("kill".getBytes()).getInt());
+            s = new Socket();
+            s.setSoLinger(false, 10);
+            s.setSoTimeout(20000);
+            s.connect(new InetSocketAddress(host, port));
+
+            InputStream is = s.getInputStream();
+            OutputStream os = s.getOutputStream();
+
+            os.write(reqBytes);
+            byte[] resBytes = new byte[4];
+
+            int rc = is.read(resBytes);
+            String retv = new String(resBytes);
+            System.out.println("rc=" + rc + " retv=" + retv);
+        } catch (IOException e) {
+            LOG.warn("Unexpected exception", e);
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    LOG.warn("Unexpected exception", e);
+                }
+            }
+        }
+    }
+
+    public static void setTraceMask(String host, int port, String traceMaskStr) {
+        Socket s = null;
+        try {
+            byte[] reqBytes = new byte[12];
+            ByteBuffer req = ByteBuffer.wrap(reqBytes);
+            long traceMask = Long.parseLong(traceMaskStr, 8);
+            req.putInt(ByteBuffer.wrap("stmk".getBytes()).getInt());
+            req.putLong(traceMask);
+
+            s = new Socket();
+            s.setSoLinger(false, 10);
+            s.setSoTimeout(20000);
+            s.connect(new InetSocketAddress(host, port));
+
+            InputStream is = s.getInputStream();
+            OutputStream os = s.getOutputStream();
+
+            os.write(reqBytes);
+
+            byte[] resBytes = new byte[8];
+
+            int rc = is.read(resBytes);
+            ByteBuffer res = ByteBuffer.wrap(resBytes);
+            long retv = res.getLong();
+            System.out.println("rc=" + rc + " retv=0"
+                    + Long.toOctalString(retv) + " masks=0"
+                    + Long.toOctalString(traceMask));
+            assert (retv == traceMask);
+        } catch (IOException e) {
+            LOG.warn("Unexpected exception", e);
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    LOG.warn("Unexpected exception", e);
+                }
+            }
+        }
+    }
+
+    public static void getTraceMask(String host, int port) {
+        Socket s = null;
+        try {
+            byte[] reqBytes = new byte[12];
+            ByteBuffer req = ByteBuffer.wrap(reqBytes);
+            req.putInt(ByteBuffer.wrap("gtmk".getBytes()).getInt());
+
+            s = new Socket();
+            s.setSoLinger(false, 10);
+            s.setSoTimeout(20000);
+            s.connect(new InetSocketAddress(host, port));
+
+            InputStream is = s.getInputStream();
+            OutputStream os = s.getOutputStream();
+
+            os.write(reqBytes);
+
+            byte[] resBytes = new byte[8];
+
+            int rc = is.read(resBytes);
+            ByteBuffer res = ByteBuffer.wrap(resBytes);
+            long retv = res.getLong();
+            System.out.println("rc=" + rc + " retv=0"
+                    + Long.toOctalString(retv));
+        } catch (IOException e) {
+            LOG.warn("Unexpected exception", e);
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    LOG.warn("Unexpected exception", e);
+                }
+            }
+        }
+    }
+
+    private static void usage() {
+        System.out
+                .println("usage: java [-cp CLASSPATH] org.apache.zookeeper.ServerAdminClient "
+                        + "host port op (ruok|stat|dump|kill|gettracemask|settracemask) [arguments]");
+
+    }
+
+    public static void main(String[] args) {
+        if (args.length < 3) {
+            usage();
+            return;
+        }
+        String host = args[0];
+        int port = Integer.parseInt(args[1]);
+        String op = args[2];
+        if (op.equalsIgnoreCase("gettracemask")) {
+            getTraceMask(host, port);
+        } else if (op.equalsIgnoreCase("settracemask")) {
+            setTraceMask(host, port, args[3]);
+        } else if (op.equalsIgnoreCase("ruok")) {
+            ruok(host, port);
+        } else if (op.equalsIgnoreCase("kill")) {
+            kill(host, port);
+        } else if (op.equalsIgnoreCase("stat")) {
+            stat(host, port);
+        } else if (op.equalsIgnoreCase("dump")) {
+            dump(host, port);
+        } else {
+            System.out.println("Unrecognized op: " + op);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/Shell.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/Shell.java b/zookeeper-server/src/main/java/org/apache/zookeeper/Shell.java
new file mode 100644
index 0000000..246170e
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/Shell.java
@@ -0,0 +1,477 @@
+/**
+ * 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.
+ */
+
+/* This file copied from Hadoop's security branch,
+  * with the following changes:
+  * 1. package changed from org.apache.hadoop.util to
+  *    org.apache.zookeeper.
+  * 2. Usage of Hadoop's Configuration class removed since
+  *    it is not available in Zookeeper: instead, system properties
+  *    are used.
+  * 3. The deprecated getUlimitMemoryCommand() method removed since
+  *    it is not needed.
+  */
+
+
+package org.apache.zookeeper;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.common.Time;
+
+/**
+ * A base class for running a Unix command.
+ * 
+ * <code>Shell</code> can be used to run unix commands like <code>du</code> or
+ * <code>df</code>. It also offers facilities to gate commands by 
+ * time-intervals.
+ */
+abstract public class Shell {
+  
+  Logger LOG = Logger.getLogger(Shell.class);
+  
+  /** a Unix command to get the current user's name */
+  public final static String USER_NAME_COMMAND = "whoami";
+  /** a Unix command to get the current user's groups list */
+  public static String[] getGroupsCommand() {
+    return new String[]{"bash", "-c", "groups"};
+  }
+  /** a Unix command to get a given user's groups list */
+  public static String[] getGroupsForUserCommand(final String user) {
+    //'groups username' command return is non-consistent across different unixes
+    return new String [] {"bash", "-c", "id -Gn " + user};
+  }
+  /** a Unix command to set permission */
+  public static final String SET_PERMISSION_COMMAND = "chmod";
+  /** a Unix command to set owner */
+  public static final String SET_OWNER_COMMAND = "chown";
+  public static final String SET_GROUP_COMMAND = "chgrp";
+  /** Return a Unix command to get permission information. */
+  public static String[] getGET_PERMISSION_COMMAND() {
+    //force /bin/ls, except on windows.
+    return new String[] {(WINDOWS ? "ls" : "/bin/ls"), "-ld"};
+  }
+
+  /**Time after which the executing script would be timedout*/
+  protected long timeOutInterval = 0L;
+  /** If or not script timed out*/
+  private AtomicBoolean timedOut;
+
+  /** a Unix command to get ulimit of a process. */
+  public static final String ULIMIT_COMMAND = "ulimit";
+  
+  /** 
+   * Get the Unix command for setting the maximum virtual memory available
+   * to a given child process. This is only relevant when we are forking a
+   * process from within the Mapper or the Reducer implementations.
+   * Also see Hadoop Pipes and Hadoop Streaming.
+   * 
+   * It also checks to ensure that we are running on a *nix platform else 
+   * (e.g. in Cygwin/Windows) it returns <code>null</code>.
+   * @param memoryLimit virtual memory limit
+   * @return a <code>String[]</code> with the ulimit command arguments or 
+   *         <code>null</code> if we are running on a non *nix platform or
+   *         if the limit is unspecified.
+   */
+  public static String[] getUlimitMemoryCommand(int memoryLimit) {
+    // ulimit isn't supported on Windows
+    if (WINDOWS) {
+      return null;
+    }
+    
+    return new String[] {ULIMIT_COMMAND, "-v", String.valueOf(memoryLimit)};
+  }
+
+  /** Set to true on Windows platforms */
+  public static final boolean WINDOWS /* borrowed from Path.WINDOWS */
+                = System.getProperty("os.name").startsWith("Windows");
+  
+  private long    interval;   // refresh interval in msec
+  private long    lastTime;   // last time the command was performed
+  private Map<String, String> environment; // env for the command execution
+  private File dir;
+  private Process process; // sub process used to execute the command
+  private int exitCode;
+
+  /**If or not script finished executing*/
+  private volatile AtomicBoolean completed;
+  
+  public Shell() {
+    this(0L);
+  }
+  
+  /**
+   * @param interval the minimum duration to wait before re-executing the 
+   *        command.
+   */
+  public Shell( long interval ) {
+    this.interval = interval;
+    this.lastTime = (interval<0) ? 0 : -interval;
+  }
+  
+  /** set the environment for the command 
+   * @param env Mapping of environment variables
+   */
+  protected void setEnvironment(Map<String, String> env) {
+    this.environment = env;
+  }
+
+  /** set the working directory 
+   * @param dir The directory where the command would be executed
+   */
+  protected void setWorkingDirectory(File dir) {
+    this.dir = dir;
+  }
+
+  /** check to see if a command needs to be executed and execute if needed */
+  protected void run() throws IOException {
+    if (lastTime + interval > Time.currentElapsedTime())
+      return;
+    exitCode = 0; // reset for next run
+    runCommand();
+  }
+
+  /** Run a command */
+  private void runCommand() throws IOException { 
+    ProcessBuilder builder = new ProcessBuilder(getExecString());
+    Timer timeOutTimer = null;
+    ShellTimeoutTimerTask timeoutTimerTask = null;
+    timedOut = new AtomicBoolean(false);
+    completed = new AtomicBoolean(false);
+    
+    if (environment != null) {
+      builder.environment().putAll(this.environment);
+    }
+    if (dir != null) {
+      builder.directory(this.dir);
+    }
+    
+    process = builder.start();
+    if (timeOutInterval > 0) {
+      timeOutTimer = new Timer();
+      timeoutTimerTask = new ShellTimeoutTimerTask(
+          this);
+      //One time scheduling.
+      timeOutTimer.schedule(timeoutTimerTask, timeOutInterval);
+    }
+    final BufferedReader errReader = 
+            new BufferedReader(new InputStreamReader(process
+                                                     .getErrorStream()));
+    BufferedReader inReader = 
+            new BufferedReader(new InputStreamReader(process
+                                                     .getInputStream()));
+    final StringBuffer errMsg = new StringBuffer();
+    
+    // read error and input streams as this would free up the buffers
+    // free the error stream buffer
+    Thread errThread = new Thread() {
+      @Override
+      public void run() {
+        try {
+          String line = errReader.readLine();
+          while((line != null) && !isInterrupted()) {
+            errMsg.append(line);
+            errMsg.append(System.getProperty("line.separator"));
+            line = errReader.readLine();
+          }
+        } catch(IOException ioe) {
+          LOG.warn("Error reading the error stream", ioe);
+        }
+      }
+    };
+    try {
+      errThread.start();
+    } catch (IllegalStateException ise) { }
+    try {
+      parseExecResult(inReader); // parse the output
+      // clear the input stream buffer
+      String line = inReader.readLine();
+      while(line != null) { 
+        line = inReader.readLine();
+      }
+      // wait for the process to finish and check the exit code
+      exitCode  = process.waitFor();
+      try {
+        // make sure that the error thread exits
+        errThread.join();
+      } catch (InterruptedException ie) {
+        LOG.warn("Interrupted while reading the error stream", ie);
+      }
+      completed.set(true);
+      //the timeout thread handling
+      //taken care in finally block
+      if (exitCode != 0) {
+        throw new ExitCodeException(exitCode, errMsg.toString());
+      }
+    } catch (InterruptedException ie) {
+      throw new IOException(ie.toString());
+    } finally {
+      if ((timeOutTimer!=null) && !timedOut.get()) {
+        timeOutTimer.cancel();
+      }
+      // close the input stream
+      try {
+        inReader.close();
+      } catch (IOException ioe) {
+        LOG.warn("Error while closing the input stream", ioe);
+      }
+      if (!completed.get()) {
+        errThread.interrupt();
+      }
+      try {
+        errReader.close();
+      } catch (IOException ioe) {
+        LOG.warn("Error while closing the error stream", ioe);
+      }
+      process.destroy();
+      lastTime = Time.currentElapsedTime();
+    }
+  }
+
+  /** return an array containing the command name & its parameters */ 
+  protected abstract String[] getExecString();
+  
+  /** Parse the execution result */
+  protected abstract void parseExecResult(BufferedReader lines)
+  throws IOException;
+
+  /** get the current sub-process executing the given command 
+   * @return process executing the command
+   */
+  public Process getProcess() {
+    return process;
+  }
+
+  /** get the exit code 
+   * @return the exit code of the process
+   */
+  public int getExitCode() {
+    return exitCode;
+  }
+
+  /**
+   * This is an IOException with exit code added.
+   */
+  @SuppressWarnings("serial")
+  public static class ExitCodeException extends IOException {
+    int exitCode;
+    
+    public ExitCodeException(int exitCode, String message) {
+      super(message);
+      this.exitCode = exitCode;
+    }
+    
+    public int getExitCode() {
+      return exitCode;
+    }
+  }
+  
+  /**
+   * A simple shell command executor.
+   * 
+   * <code>ShellCommandExecutor</code>should be used in cases where the output 
+   * of the command needs no explicit parsing and where the command, working 
+   * directory and the environment remains unchanged. The output of the command 
+   * is stored as-is and is expected to be small.
+   */
+  public static class ShellCommandExecutor extends Shell {
+    
+    private String[] command;
+    private StringBuffer output;
+    
+    
+    public ShellCommandExecutor(String[] execString) {
+      this(execString, null);
+    }
+    
+    public ShellCommandExecutor(String[] execString, File dir) {
+      this(execString, dir, null);
+    }
+   
+    public ShellCommandExecutor(String[] execString, File dir, 
+                                 Map<String, String> env) {
+      this(execString, dir, env , 0L);
+    }
+
+    /**
+     * Create a new instance of the ShellCommandExecutor to execute a command.
+     * 
+     * @param execString The command to execute with arguments
+     * @param dir If not-null, specifies the directory which should be set
+     *            as the current working directory for the command.
+     *            If null, the current working directory is not modified.
+     * @param env If not-null, environment of the command will include the
+     *            key-value pairs specified in the map. If null, the current
+     *            environment is not modified.
+     * @param timeout Specifies the time in milliseconds, after which the
+     *                command will be killed and the status marked as timedout.
+     *                If 0, the command will not be timed out. 
+     */
+    public ShellCommandExecutor(String[] execString, File dir, 
+        Map<String, String> env, long timeout) {
+      command = execString.clone();
+      if (dir != null) {
+        setWorkingDirectory(dir);
+      }
+      if (env != null) {
+        setEnvironment(env);
+      }
+      timeOutInterval = timeout;
+    }
+        
+
+    /** Execute the shell command. */
+    public void execute() throws IOException {
+      this.run();    
+    }
+
+    protected String[] getExecString() {
+      return command;
+    }
+
+    protected void parseExecResult(BufferedReader lines) throws IOException {
+      output = new StringBuffer();
+      char[] buf = new char[512];
+      int nRead;
+      while ( (nRead = lines.read(buf, 0, buf.length)) > 0 ) {
+        output.append(buf, 0, nRead);
+      }
+    }
+    
+    /** Get the output of the shell command.*/
+    public String getOutput() {
+      return (output == null) ? "" : output.toString();
+    }
+
+    /**
+     * Returns the commands of this instance.
+     * Arguments with spaces in are presented with quotes round; other
+     * arguments are presented raw
+     *
+     * @return a string representation of the object.
+     */
+    public String toString() {
+      StringBuilder builder = new StringBuilder();
+      String[] args = getExecString();
+      for (String s : args) {
+        if (s.indexOf(' ') >= 0) {
+          builder.append('"').append(s).append('"');
+        } else {
+          builder.append(s);
+        }
+        builder.append(' ');
+      }
+      return builder.toString();
+    }
+  }
+  
+  /**
+   * To check if the passed script to shell command executor timed out or
+   * not.
+   * 
+   * @return if the script timed out.
+   */
+  public boolean isTimedOut() {
+    return timedOut.get();
+  }
+  
+  /**
+   * Set if the command has timed out.
+   * 
+   */
+  private void setTimedOut() {
+    this.timedOut.set(true);
+  }
+  
+  /** 
+   * Static method to execute a shell command. 
+   * Covers most of the simple cases without requiring the user to implement  
+   * the <code>Shell</code> interface.
+   * @param cmd shell command to execute.
+   * @return the output of the executed command.
+   */
+  public static String execCommand(String ... cmd) throws IOException {
+    return execCommand(null, cmd, 0L);
+  }
+  
+  /** 
+   * Static method to execute a shell command. 
+   * Covers most of the simple cases without requiring the user to implement  
+   * the <code>Shell</code> interface.
+   * @param env the map of environment key=value
+   * @param cmd shell command to execute.
+   * @param timeout time in milliseconds after which script should be marked timeout
+   * @return the output of the executed command.o
+   */
+  
+  public static String execCommand(Map<String, String> env, String[] cmd,
+      long timeout) throws IOException {
+    ShellCommandExecutor exec = new ShellCommandExecutor(cmd, null, env, 
+                                                          timeout);
+    exec.execute();
+    return exec.getOutput();
+  }
+
+  /** 
+   * Static method to execute a shell command. 
+   * Covers most of the simple cases without requiring the user to implement  
+   * the <code>Shell</code> interface.
+   * @param env the map of environment key=value
+   * @param cmd shell command to execute.
+   * @return the output of the executed command.
+   */
+  public static String execCommand(Map<String,String> env, String ... cmd) 
+  throws IOException {
+    return execCommand(env, cmd, 0L);
+  }
+  
+  /**
+   * Timer which is used to timeout scripts spawned off by shell.
+   */
+  private static class ShellTimeoutTimerTask extends TimerTask {
+
+    private Shell shell;
+
+    public ShellTimeoutTimerTask(Shell shell) {
+      this.shell = shell;
+    }
+
+    @Override
+    public void run() {
+      Process p = shell.getProcess();
+      try {
+        p.exitValue();
+      } catch (Exception e) {
+        //Process has not terminated.
+        //So check if it has completed 
+        //if not just destroy it.
+        if (p != null && !shell.completed.get()) {
+          shell.setTimedOut();
+          p.destroy();
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/StatsTrack.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/StatsTrack.java b/zookeeper-server/src/main/java/org/apache/zookeeper/StatsTrack.java
new file mode 100644
index 0000000..623c6d4
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/StatsTrack.java
@@ -0,0 +1,101 @@
+/**
+ * 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;
+
+/**
+ * a class that represents the stats associated with quotas
+ */
+public class StatsTrack {
+    private int count;
+    private long bytes;
+    private String countStr = "count";
+    private String byteStr = "bytes";
+
+    /**
+     * a default constructor for
+     * stats
+     */
+    public StatsTrack() {
+        this(null);
+    }
+    /**
+     * the stat string should be of the form count=int,bytes=long
+     * if stats is called with null the count and bytes are initialized
+     * to -1.
+     * @param stats the stat string to be intialized with
+     */
+    public StatsTrack(String stats) {
+        if (stats == null) {
+            stats = "count=-1,bytes=-1";
+        }
+        String[] split = stats.split(",");
+        if (split.length != 2) {
+            throw new IllegalArgumentException("invalid string " + stats);
+        }
+        count = Integer.parseInt(split[0].split("=")[1]);
+        bytes = Long.parseLong(split[1].split("=")[1]);
+    }
+
+
+    /**
+     * get the count of nodes allowed as part of quota
+     *
+     * @return the count as part of this string
+     */
+    public int getCount() {
+        return this.count;
+    }
+
+    /**
+     * set the count for this stat tracker.
+     *
+     * @param count
+     *            the count to set with
+     */
+    public void setCount(int count) {
+        this.count = count;
+    }
+
+    /**
+     * get the count of bytes allowed as part of quota
+     *
+     * @return the bytes as part of this string
+     */
+    public long getBytes() {
+        return this.bytes;
+    }
+
+    /**
+     * set teh bytes for this stat tracker.
+     *
+     * @param bytes
+     *            the bytes to set with
+     */
+    public void setBytes(long bytes) {
+        this.bytes = bytes;
+    }
+
+    @Override
+    /*
+     * returns the string that maps to this stat tracking.
+     */
+    public String toString() {
+        return countStr + "=" + count + "," + byteStr + "=" + bytes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/Testable.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/Testable.java b/zookeeper-server/src/main/java/org/apache/zookeeper/Testable.java
new file mode 100644
index 0000000..b38d2c3
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/Testable.java
@@ -0,0 +1,29 @@
+/**
+ * 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;
+
+/**
+ * Abstraction that exposes various methods useful for testing ZooKeeper
+ */
+public interface Testable {
+    /**
+     * Cause the ZooKeeper instance to behave as if the session expired
+     */
+    void injectSessionExpiration();
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/Transaction.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/Transaction.java b/zookeeper-server/src/main/java/org/apache/zookeeper/Transaction.java
new file mode 100644
index 0000000..d8f0e01
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/Transaction.java
@@ -0,0 +1,70 @@
+/*
+ * 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.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.AsyncCallback.MultiCallback;
+import org.apache.zookeeper.data.ACL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides a builder style interface for doing multiple updates.  This is
+ * really just a thin layer on top of Zookeeper.multi().
+ *
+ * @since 3.4.0
+ *
+ */
+@InterfaceAudience.Public
+public class Transaction {
+    private ZooKeeper zk;
+    private List<Op> ops = new ArrayList<Op>();
+
+    protected Transaction(ZooKeeper zk) {
+        this.zk = zk;
+    }
+
+    public Transaction create(final String path, byte data[], List<ACL> acl,
+                              CreateMode createMode) {
+        ops.add(Op.create(path, data, acl, createMode.toFlag()));
+        return this;
+    }
+
+    public Transaction delete(final String path, int version) {
+        ops.add(Op.delete(path, version));
+        return this;
+    }
+
+    public Transaction check(String path, int version) {
+        ops.add(Op.check(path, version));
+        return this;
+    }
+
+    public Transaction setData(final String path, byte data[], int version) {
+        ops.add(Op.setData(path, data, version));
+        return this;
+    }
+
+    public List<OpResult> commit() throws InterruptedException, KeeperException {
+        return zk.multi(ops);
+    }
+
+    public void commit(MultiCallback cb, Object ctx) {
+        zk.multi(ops, cb, ctx);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/Version.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/Version.java b/zookeeper-server/src/main/java/org/apache/zookeeper/Version.java
new file mode 100644
index 0000000..1f5cf1a
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/Version.java
@@ -0,0 +1,90 @@
+/**
+ * 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;
+
+public class Version implements org.apache.zookeeper.version.Info {
+
+    /*
+     * Since the SVN to Git port this field doesn't return the revision anymore
+     * TODO: remove this method and associated field declaration in VerGen
+     * @see {@link #getHashRevision()}
+     * @return the default value -1
+     */
+    @Deprecated
+    public static int getRevision() {
+        return REVISION;
+    }
+
+    public static String getRevisionHash() {
+        return REVISION_HASH;
+    }
+
+    public static String getBuildDate() {
+        return BUILD_DATE;
+    }
+
+    public static String getVersion() {
+        return MAJOR + "." + MINOR + "." + MICRO
+            + (QUALIFIER == null ? "" : "-" + QUALIFIER);
+    }
+
+    public static String getVersionRevision() {
+        return getVersion() + "-" + getRevisionHash();
+    }
+
+    public static String getFullVersion() {
+        return getVersionRevision() + ", built on " + getBuildDate();
+    }
+
+    public static void printUsage() {
+        System.out
+                .print("Usage:\tjava -cp ... org.apache.zookeeper.Version "
+                        + "[--full | --short | --revision],\n\tPrints --full version "
+                        + "info if no arg specified.");
+        System.exit(1);
+    }
+
+    /**
+     * Prints the current version, revision and build date to the standard out.
+     * 
+     * @param args
+     *            <ul>
+     *            <li> --short - prints a short version string "1.2.3"
+     *            <li> --revision - prints a short version string with the SVN
+     *            repository revision "1.2.3-94"
+     *            <li> --full - prints the revision and the build date
+     *            </ul>
+     */
+    public static void main(String[] args) {
+        if (args.length > 1) {
+            printUsage();
+        }
+        if (args.length == 0 || (args.length == 1 && args[0].equals("--full"))) {
+            System.out.println(getFullVersion());
+            System.exit(0);
+        }
+        if (args[0].equals("--short"))
+            System.out.println(getVersion());
+        else if (args[0].equals("--revision"))
+            System.out.println(getVersionRevision());
+        else
+            printUsage();
+        System.exit(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/WatchedEvent.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/WatchedEvent.java b/zookeeper-server/src/main/java/org/apache/zookeeper/WatchedEvent.java
new file mode 100644
index 0000000..851fc6c
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/WatchedEvent.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;
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.proto.WatcherEvent;
+import org.apache.zookeeper.Watcher.Event.EventType;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+
+/**
+ *  A WatchedEvent represents a change on the ZooKeeper that a Watcher
+ *  is able to respond to.  The WatchedEvent includes exactly what happened,
+ *  the current state of the ZooKeeper, and the path of the znode that
+ *  was involved in the event.
+ */
+@InterfaceAudience.Public
+public class WatchedEvent {
+    final private KeeperState keeperState;
+    final private EventType eventType;
+    private String path;
+    
+    /**
+     * Create a WatchedEvent with specified type, state and path
+     */
+    public WatchedEvent(EventType eventType, KeeperState keeperState, String path) {
+        this.keeperState = keeperState;
+        this.eventType = eventType;
+        this.path = path;
+    }
+    
+    /**
+     * Convert a WatcherEvent sent over the wire into a full-fledged WatcherEvent
+     */
+    public WatchedEvent(WatcherEvent eventMessage) {
+        keeperState = KeeperState.fromInt(eventMessage.getState());
+        eventType = EventType.fromInt(eventMessage.getType());
+        path = eventMessage.getPath();
+    }
+    
+    public KeeperState getState() {
+        return keeperState;
+    }
+    
+    public EventType getType() {
+        return eventType;
+    }
+    
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    public String toString() {
+        return "WatchedEvent state:" + keeperState
+            + " type:" + eventType + " path:" + path;
+    }
+
+    /**
+     *  Convert WatchedEvent to type that can be sent over network
+     */
+    public WatcherEvent getWrapper() {
+        return new WatcherEvent(eventType.getIntValue(), 
+                                keeperState.getIntValue(), 
+                                path);
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/Watcher.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/Watcher.java b/zookeeper-server/src/main/java/org/apache/zookeeper/Watcher.java
new file mode 100644
index 0000000..5c21485
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/Watcher.java
@@ -0,0 +1,155 @@
+/**
+ * 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.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * This interface specifies the public interface an event handler class must
+ * implement. A ZooKeeper client will get various events from the ZooKeeper
+ * server it connects to. An application using such a client handles these
+ * events by registering a callback object with the client. The callback object
+ * is expected to be an instance of a class that implements Watcher interface.
+ * 
+ */
+@InterfaceAudience.Public
+public interface Watcher {
+
+    /**
+     * This interface defines the possible states an Event may represent
+     */
+    @InterfaceAudience.Public
+    public interface Event {
+        /**
+         * Enumeration of states the ZooKeeper may be at the event
+         */
+        @InterfaceAudience.Public
+        public enum KeeperState {
+            /** Unused, this state is never generated by the server */
+            @Deprecated
+            Unknown (-1),
+
+            /** The client is in the disconnected state - it is not connected
+             * to any server in the ensemble. */
+            Disconnected (0),
+
+            /** Unused, this state is never generated by the server */
+            @Deprecated
+            NoSyncConnected (1),
+
+            /** The client is in the connected state - it is connected
+             * to a server in the ensemble (one of the servers specified
+             * in the host connection parameter during ZooKeeper client
+             * creation). */
+            SyncConnected (3),
+
+            /**
+             * Auth failed state
+             */
+            AuthFailed (4),
+
+            /**
+             * The client is connected to a read-only server, that is the
+             * server which is not currently connected to the majority.
+             * The only operations allowed after receiving this state is
+             * read operations.
+             * This state is generated for read-only clients only since
+             * read/write clients aren't allowed to connect to r/o servers.
+             */
+            ConnectedReadOnly (5),
+
+            /**
+              * SaslAuthenticated: used to notify clients that they are SASL-authenticated,
+              * so that they can perform Zookeeper actions with their SASL-authorized permissions.
+              */
+            SaslAuthenticated(6),
+
+            /** The serving cluster has expired this session. The ZooKeeper
+             * client connection (the session) is no longer valid. You must
+             * create a new client connection (instantiate a new ZooKeeper
+             * instance) if you with to access the ensemble. */
+            Expired (-112);
+
+            private final int intValue;     // Integer representation of value
+                                            // for sending over wire
+
+            KeeperState(int intValue) {
+                this.intValue = intValue;
+            }
+
+            public int getIntValue() {
+                return intValue;
+            }
+
+            public static KeeperState fromInt(int intValue) {
+                switch(intValue) {
+                    case   -1: return KeeperState.Unknown;
+                    case    0: return KeeperState.Disconnected;
+                    case    1: return KeeperState.NoSyncConnected;
+                    case    3: return KeeperState.SyncConnected;
+                    case    4: return KeeperState.AuthFailed;
+                    case    5: return KeeperState.ConnectedReadOnly;
+                    case    6: return KeeperState.SaslAuthenticated;
+                    case -112: return KeeperState.Expired;
+
+                    default:
+                        throw new RuntimeException("Invalid integer value for conversion to KeeperState");
+                }
+            }
+        }
+
+        /**
+         * Enumeration of types of events that may occur on the ZooKeeper
+         */
+        @InterfaceAudience.Public
+        public enum EventType {
+            None (-1),
+            NodeCreated (1),
+            NodeDeleted (2),
+            NodeDataChanged (3),
+            NodeChildrenChanged (4);
+
+            private final int intValue;     // Integer representation of value
+                                            // for sending over wire
+
+            EventType(int intValue) {
+                this.intValue = intValue;
+            }
+
+            public int getIntValue() {
+                return intValue;
+            }
+
+            public static EventType fromInt(int intValue) {
+                switch(intValue) {
+                    case -1: return EventType.None;
+                    case  1: return EventType.NodeCreated;
+                    case  2: return EventType.NodeDeleted;
+                    case  3: return EventType.NodeDataChanged;
+                    case  4: return EventType.NodeChildrenChanged;
+
+                    default:
+                        throw new RuntimeException("Invalid integer value for conversion to EventType");
+                }
+            }           
+        }
+    }
+
+    abstract public void process(WatchedEvent event);
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/ZKUtil.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZKUtil.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZKUtil.java
new file mode 100644
index 0000000..e901832
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZKUtil.java
@@ -0,0 +1,124 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.zookeeper.AsyncCallback.VoidCallback;
+import org.apache.zookeeper.common.PathUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+         
+public class ZKUtil {
+    private static final Logger LOG = LoggerFactory.getLogger(ZKUtil.class);
+    /**
+     * Recursively delete the node with the given path. 
+     * <p>
+     * Important: All versions, of all nodes, under the given node are deleted.
+     * <p>
+     * If there is an error with deleting one of the sub-nodes in the tree, 
+     * this operation would abort and would be the responsibility of the app to handle the same.
+     * 
+     * See {@link #delete(String, int)} for more details.
+     * 
+     * @throws IllegalArgumentException if an invalid path is specified
+     */
+    public static void deleteRecursive(ZooKeeper zk, final String pathRoot)
+        throws InterruptedException, KeeperException
+    {
+        PathUtils.validatePath(pathRoot);
+      
+        List<String> tree = listSubTreeBFS(zk, pathRoot);
+        LOG.debug("Deleting " + tree);
+        LOG.debug("Deleting " + tree.size() + " subnodes ");
+        for (int i = tree.size() - 1; i >= 0 ; --i) {
+            //Delete the leaves first and eventually get rid of the root
+            zk.delete(tree.get(i), -1); //Delete all versions of the node with -1.
+        }
+    }
+    
+
+    /**
+     * Recursively delete the node with the given path. (async version).
+     * 
+     * <p>
+     * Important: All versions, of all nodes, under the given node are deleted.
+     * <p>
+     * If there is an error with deleting one of the sub-nodes in the tree, 
+     * this operation would abort and would be the responsibility of the app to handle the same.
+     * <p>
+     * @param zk the zookeeper handle
+     * @param pathRoot the path to be deleted
+     * @param cb call back method
+     * @param ctx the context the callback method is called with
+     * @throws IllegalArgumentException if an invalid path is specified
+     */
+    public static void deleteRecursive(ZooKeeper zk, final String pathRoot, VoidCallback cb,
+        Object ctx)
+        throws InterruptedException, KeeperException
+    {
+        PathUtils.validatePath(pathRoot);
+      
+        List<String> tree = listSubTreeBFS(zk, pathRoot);
+        LOG.debug("Deleting " + tree);
+        LOG.debug("Deleting " + tree.size() + " subnodes ");
+        for (int i = tree.size() - 1; i >= 0 ; --i) {
+            //Delete the leaves first and eventually get rid of the root
+            zk.delete(tree.get(i), -1, cb, ctx); //Delete all versions of the node with -1.
+        }
+    }
+    
+    /**
+     * BFS Traversal of the system under pathRoot, with the entries in the list, in the 
+     * same order as that of the traversal.
+     * <p>
+     * <b>Important:</b> This is <i>not an atomic snapshot</i> of the tree ever, but the
+     *  state as it exists across multiple RPCs from zkClient to the ensemble.
+     * For practical purposes, it is suggested to bring the clients to the ensemble 
+     * down (i.e. prevent writes to pathRoot) to 'simulate' a snapshot behavior.   
+     * 
+     * @param zk the zookeeper handle
+     * @param pathRoot The znode path, for which the entire subtree needs to be listed.
+     * @throws InterruptedException 
+     * @throws KeeperException 
+     */
+    public static List<String> listSubTreeBFS(ZooKeeper zk, final String pathRoot) throws 
+        KeeperException, InterruptedException {
+        Deque<String> queue = new LinkedList<String>();
+        List<String> tree = new ArrayList<String>();
+        queue.add(pathRoot);
+        tree.add(pathRoot);
+        while (true) {
+            String node = queue.pollFirst();
+            if (node == null) {
+                break;
+            }
+            List<String> children = zk.getChildren(node, false);
+            for (final String child : children) {
+                final String childPath = node + "/" + child;
+                queue.add(childPath);
+                tree.add(childPath);
+            }
+        }
+        return tree;
+    }
+    
+} 

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/7291e47c/zookeeper-server/src/main/java/org/apache/zookeeper/ZooDefs.java
----------------------------------------------------------------------
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooDefs.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooDefs.java
new file mode 100644
index 0000000..09bc95c
--- /dev/null
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooDefs.java
@@ -0,0 +1,125 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+
+@InterfaceAudience.Public
+public class ZooDefs {
+
+    @InterfaceAudience.Public
+    public interface OpCode {
+        public final int notification = 0;
+
+        public final int create = 1;
+
+        public final int delete = 2;
+
+        public final int exists = 3;
+
+        public final int getData = 4;
+
+        public final int setData = 5;
+
+        public final int getACL = 6;
+
+        public final int setACL = 7;
+
+        public final int getChildren = 8;
+
+        public final int sync = 9;
+
+        public final int ping = 11;
+
+        public final int getChildren2 = 12;
+
+        public final int check = 13;
+
+        public final int multi = 14;
+
+        public final int auth = 100;
+
+        public final int setWatches = 101;
+
+        public final int sasl = 102;
+
+        public final int createSession = -10;
+
+        public final int closeSession = -11;
+
+        public final int error = -1;
+    }
+
+    @InterfaceAudience.Public
+    public interface Perms {
+        int READ = 1 << 0;
+
+        int WRITE = 1 << 1;
+
+        int CREATE = 1 << 2;
+
+        int DELETE = 1 << 3;
+
+        int ADMIN = 1 << 4;
+
+        int ALL = READ | WRITE | CREATE | DELETE | ADMIN;
+    }
+
+    @InterfaceAudience.Public
+    public interface Ids {
+        /**
+         * This Id represents anyone.
+         */
+        public final Id ANYONE_ID_UNSAFE = new Id("world", "anyone");
+
+        /**
+         * This Id is only usable to set ACLs. It will get substituted with the
+         * Id's the client authenticated with.
+         */
+        public final Id AUTH_IDS = new Id("auth", "");
+
+        /**
+         * This is a completely open ACL .
+         */
+        public final ArrayList<ACL> OPEN_ACL_UNSAFE = new ArrayList<ACL>(
+                Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));
+
+        /**
+         * This ACL gives the creators authentication id's all permissions.
+         */
+        public final ArrayList<ACL> CREATOR_ALL_ACL = new ArrayList<ACL>(
+                Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));
+
+        /**
+         * This ACL gives the world the ability to read.
+         */
+        public final ArrayList<ACL> READ_ACL_UNSAFE = new ArrayList<ACL>(
+                Collections
+                        .singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));
+    }
+
+    final public static String[] opNames = { "notification", "create",
+            "delete", "exists", "getData", "setData", "getACL", "setACL",
+            "getChildren", "getChildren2", "getMaxChildren", "setMaxChildren", "ping" };
+}


Mime
View raw message